to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq*/\n/**\n * Upload handler used that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to\n * a generic server.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.traditional = qq.traditional || {};\nqq.traditional.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log;\n\n /**\n * Returns json object received by iframe from server.\n */\n function getIframeContentJson(id, iframe) {\n /*jshint evil: true*/\n\n var response, doc, innerHtml;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n log(\"converting iframe's innerHTML to JSON\");\n log(\"innerHTML = \" + innerHtml);\n //plain text response may be wrapped in tag\n if (innerHtml && innerHtml.match(/^>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);\n }\n } else if (thatWords.length > 0xffff) {\n // Copy one word at a time\n for (var i = 0; i < thatSigBytes; i += 4) {\n thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];\n }\n } else {\n // Copy all words at once\n thisWords.push.apply(thisWords, thatWords);\n }\n this.sigBytes += thatSigBytes;\n\n // Chainable\n return this;\n },\n\n /**\n * Removes insignificant bits.\n *\n * @example\n *\n * wordArray.clamp();\n */\n clamp: function () {\n // Shortcuts\n var words = this.words;\n var sigBytes = this.sigBytes;\n\n // Clamp\n words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);\n words.length = Math.ceil(sigBytes / 4);\n },\n\n /**\n * Creates a copy of this word array.\n *\n * @return {WordArray} The clone.\n *\n * @example\n *\n * var clone = wordArray.clone();\n */\n clone: function () {\n var clone = Base.clone.call(this);\n clone.words = this.words.slice(0);\n\n return clone;\n },\n\n /**\n * Creates a word array filled with random bytes.\n *\n * @param {number} nBytes The number of random bytes to generate.\n *\n * @return {WordArray} The random word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.lib.WordArray.random(16);\n */\n random: function (nBytes) {\n var words = [];\n for (var i = 0; i < nBytes; i += 4) {\n words.push((Math.random() * 0x100000000) | 0);\n }\n\n return new WordArray.init(words, nBytes);\n }\n });\n\n /**\n * Encoder namespace.\n */\n var C_enc = C.enc = {};\n\n /**\n * Hex encoding strategy.\n */\n var Hex = C_enc.Hex = {\n /**\n * Converts a word array to a hex string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The hex string.\n *\n * @static\n *\n * @example\n *\n * var hexString = CryptoJS.enc.Hex.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n\n // Convert\n var hexChars = [];\n for (var i = 0; i < sigBytes; i++) {\n var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n hexChars.push((bite >>> 4).toString(16));\n hexChars.push((bite & 0x0f).toString(16));\n }\n\n return hexChars.join('');\n },\n\n /**\n * Converts a hex string to a word array.\n *\n * @param {string} hexStr The hex string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Hex.parse(hexString);\n */\n parse: function (hexStr) {\n // Shortcut\n var hexStrLength = hexStr.length;\n\n // Convert\n var words = [];\n for (var i = 0; i < hexStrLength; i += 2) {\n words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);\n }\n\n return new WordArray.init(words, hexStrLength / 2);\n }\n };\n\n /**\n * Latin1 encoding strategy.\n */\n var Latin1 = C_enc.Latin1 = {\n /**\n * Converts a word array to a Latin1 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Latin1 string.\n *\n * @static\n *\n * @example\n *\n * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n\n // Convert\n var latin1Chars = [];\n for (var i = 0; i < sigBytes; i++) {\n var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n latin1Chars.push(String.fromCharCode(bite));\n }\n\n return latin1Chars.join('');\n },\n\n /**\n * Converts a Latin1 string to a word array.\n *\n * @param {string} latin1Str The Latin1 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Latin1.parse(latin1String);\n */\n parse: function (latin1Str) {\n // Shortcut\n var latin1StrLength = latin1Str.length;\n\n // Convert\n var words = [];\n for (var i = 0; i < latin1StrLength; i++) {\n words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);\n }\n\n return new WordArray.init(words, latin1StrLength);\n }\n };\n\n /**\n * UTF-8 encoding strategy.\n */\n var Utf8 = C_enc.Utf8 = {\n /**\n * Converts a word array to a UTF-8 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The UTF-8 string.\n *\n * @static\n *\n * @example\n *\n * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);\n */\n stringify: function (wordArray) {\n try {\n return decodeURIComponent(escape(Latin1.stringify(wordArray)));\n } catch (e) {\n throw new Error('Malformed UTF-8 data');\n }\n },\n\n /**\n * Converts a UTF-8 string to a word array.\n *\n * @param {string} utf8Str The UTF-8 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Utf8.parse(utf8String);\n */\n parse: function (utf8Str) {\n return Latin1.parse(unescape(encodeURIComponent(utf8Str)));\n }\n };\n\n /**\n * Abstract buffered block algorithm template.\n *\n * The property blockSize must be implemented in a concrete subtype.\n *\n * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0\n */\n var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({\n /**\n * Resets this block algorithm's data buffer to its initial state.\n *\n * @example\n *\n * bufferedBlockAlgorithm.reset();\n */\n reset: function () {\n // Initial values\n this._data = new WordArray.init();\n this._nDataBytes = 0;\n },\n\n /**\n * Adds new data to this block algorithm's buffer.\n *\n * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.\n *\n * @example\n *\n * bufferedBlockAlgorithm._append('data');\n * bufferedBlockAlgorithm._append(wordArray);\n */\n _append: function (data) {\n // Convert string to WordArray, else assume WordArray already\n if (typeof data == 'string') {\n data = Utf8.parse(data);\n }\n\n // Append\n this._data.concat(data);\n this._nDataBytes += data.sigBytes;\n },\n\n /**\n * Processes available data blocks.\n *\n * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.\n *\n * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.\n *\n * @return {WordArray} The processed data.\n *\n * @example\n *\n * var processedData = bufferedBlockAlgorithm._process();\n * var processedData = bufferedBlockAlgorithm._process(!!'flush');\n */\n _process: function (doFlush) {\n // Shortcuts\n var data = this._data;\n var dataWords = data.words;\n var dataSigBytes = data.sigBytes;\n var blockSize = this.blockSize;\n var blockSizeBytes = blockSize * 4;\n\n // Count blocks ready\n var nBlocksReady = dataSigBytes / blockSizeBytes;\n if (doFlush) {\n // Round up to include partial blocks\n nBlocksReady = Math.ceil(nBlocksReady);\n } else {\n // Round down to include only full blocks,\n // less the number of blocks that must remain in the buffer\n nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);\n }\n\n // Count words ready\n var nWordsReady = nBlocksReady * blockSize;\n\n // Count bytes ready\n var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);\n\n // Process blocks\n if (nWordsReady) {\n for (var offset = 0; offset < nWordsReady; offset += blockSize) {\n // Perform concrete-algorithm logic\n this._doProcessBlock(dataWords, offset);\n }\n\n // Remove processed words\n var processedWords = dataWords.splice(0, nWordsReady);\n data.sigBytes -= nBytesReady;\n }\n\n // Return processed words\n return new WordArray.init(processedWords, nBytesReady);\n },\n\n /**\n * Creates a copy of this object.\n *\n * @return {Object} The clone.\n *\n * @example\n *\n * var clone = bufferedBlockAlgorithm.clone();\n */\n clone: function () {\n var clone = Base.clone.call(this);\n clone._data = this._data.clone();\n\n return clone;\n },\n\n _minBufferSize: 0\n });\n\n /**\n * Abstract hasher template.\n *\n * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)\n */\n var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({\n /**\n * Configuration options.\n */\n cfg: Base.extend(),\n\n /**\n * Initializes a newly created hasher.\n *\n * @param {Object} cfg (Optional) The configuration options to use for this hash computation.\n *\n * @example\n *\n * var hasher = CryptoJS.algo.SHA256.create();\n */\n init: function (cfg) {\n // Apply config defaults\n this.cfg = this.cfg.extend(cfg);\n\n // Set initial values\n this.reset();\n },\n\n /**\n * Resets this hasher to its initial state.\n *\n * @example\n *\n * hasher.reset();\n */\n reset: function () {\n // Reset data buffer\n BufferedBlockAlgorithm.reset.call(this);\n\n // Perform concrete-hasher logic\n this._doReset();\n },\n\n /**\n * Updates this hasher with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {Hasher} This hasher.\n *\n * @example\n *\n * hasher.update('message');\n * hasher.update(wordArray);\n */\n update: function (messageUpdate) {\n // Append\n this._append(messageUpdate);\n\n // Update the hash\n this._process();\n\n // Chainable\n return this;\n },\n\n /**\n * Finalizes the hash computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The hash.\n *\n * @example\n *\n * var hash = hasher.finalize();\n * var hash = hasher.finalize('message');\n * var hash = hasher.finalize(wordArray);\n */\n finalize: function (messageUpdate) {\n // Final message update\n if (messageUpdate) {\n this._append(messageUpdate);\n }\n\n // Perform concrete-hasher logic\n var hash = this._doFinalize();\n\n return hash;\n },\n\n blockSize: 512/32,\n\n /**\n * Creates a shortcut function to a hasher's object interface.\n *\n * @param {Hasher} hasher The hasher to create a helper for.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);\n */\n _createHelper: function (hasher) {\n return function (message, cfg) {\n return new hasher.init(cfg).finalize(message);\n };\n },\n\n /**\n * Creates a shortcut function to the HMAC's object interface.\n *\n * @param {Hasher} hasher The hasher to use in this HMAC helper.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);\n */\n _createHmacHelper: function (hasher) {\n return function (message, key) {\n return new C_algo.HMAC.init(hasher, key).finalize(message);\n };\n }\n });\n\n /**\n * Algorithm namespace.\n */\n var C_algo = C.algo = {};\n\n return C;\n}(Math));\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var WordArray = C_lib.WordArray;\n var C_enc = C.enc;\n\n /**\n * Base64 encoding strategy.\n */\n var Base64 = C_enc.Base64 = {\n /**\n * Converts a word array to a Base64 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Base64 string.\n *\n * @static\n *\n * @example\n *\n * var base64String = CryptoJS.enc.Base64.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n var map = this._map;\n\n // Clamp excess bits\n wordArray.clamp();\n\n // Convert\n var base64Chars = [];\n for (var i = 0; i < sigBytes; i += 3) {\n var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;\n var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;\n\n var triplet = (byte1 << 16) | (byte2 << 8) | byte3;\n\n for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {\n base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));\n }\n }\n\n // Add padding\n var paddingChar = map.charAt(64);\n if (paddingChar) {\n while (base64Chars.length % 4) {\n base64Chars.push(paddingChar);\n }\n }\n\n return base64Chars.join('');\n },\n\n /**\n * Converts a Base64 string to a word array.\n *\n * @param {string} base64Str The Base64 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Base64.parse(base64String);\n */\n parse: function (base64Str) {\n // Shortcuts\n var base64StrLength = base64Str.length;\n var map = this._map;\n\n // Ignore padding\n var paddingChar = map.charAt(64);\n if (paddingChar) {\n var paddingIndex = base64Str.indexOf(paddingChar);\n if (paddingIndex != -1) {\n base64StrLength = paddingIndex;\n }\n }\n\n // Convert\n var words = [];\n var nBytes = 0;\n for (var i = 0; i < base64StrLength; i++) {\n if (i % 4) {\n var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2);\n var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2);\n words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8);\n nBytes++;\n }\n }\n\n return WordArray.create(words, nBytes);\n },\n\n _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='\n };\n}());\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var Base = C_lib.Base;\n var C_enc = C.enc;\n var Utf8 = C_enc.Utf8;\n var C_algo = C.algo;\n\n /**\n * HMAC algorithm.\n */\n var HMAC = C_algo.HMAC = Base.extend({\n /**\n * Initializes a newly created HMAC.\n *\n * @param {Hasher} hasher The hash algorithm to use.\n * @param {WordArray|string} key The secret key.\n *\n * @example\n *\n * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);\n */\n init: function (hasher, key) {\n // Init hasher\n hasher = this._hasher = new hasher.init();\n\n // Convert string to WordArray, else assume WordArray already\n if (typeof key == 'string') {\n key = Utf8.parse(key);\n }\n\n // Shortcuts\n var hasherBlockSize = hasher.blockSize;\n var hasherBlockSizeBytes = hasherBlockSize * 4;\n\n // Allow arbitrary length keys\n if (key.sigBytes > hasherBlockSizeBytes) {\n key = hasher.finalize(key);\n }\n\n // Clamp excess bits\n key.clamp();\n\n // Clone key for inner and outer pads\n var oKey = this._oKey = key.clone();\n var iKey = this._iKey = key.clone();\n\n // Shortcuts\n var oKeyWords = oKey.words;\n var iKeyWords = iKey.words;\n\n // XOR keys with pad constants\n for (var i = 0; i < hasherBlockSize; i++) {\n oKeyWords[i] ^= 0x5c5c5c5c;\n iKeyWords[i] ^= 0x36363636;\n }\n oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;\n\n // Set initial values\n this.reset();\n },\n\n /**\n * Resets this HMAC to its initial state.\n *\n * @example\n *\n * hmacHasher.reset();\n */\n reset: function () {\n // Shortcut\n var hasher = this._hasher;\n\n // Reset\n hasher.reset();\n hasher.update(this._iKey);\n },\n\n /**\n * Updates this HMAC with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {HMAC} This HMAC instance.\n *\n * @example\n *\n * hmacHasher.update('message');\n * hmacHasher.update(wordArray);\n */\n update: function (messageUpdate) {\n this._hasher.update(messageUpdate);\n\n // Chainable\n return this;\n },\n\n /**\n * Finalizes the HMAC computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The HMAC.\n *\n * @example\n *\n * var hmac = hmacHasher.finalize();\n * var hmac = hmacHasher.finalize('message');\n * var hmac = hmacHasher.finalize(wordArray);\n */\n finalize: function (messageUpdate) {\n // Shortcut\n var hasher = this._hasher;\n\n // Compute HMAC\n var innerHash = hasher.finalize(messageUpdate);\n hasher.reset();\n var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));\n\n return hmac;\n }\n });\n}());\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var WordArray = C_lib.WordArray;\n var Hasher = C_lib.Hasher;\n var C_algo = C.algo;\n\n // Reusable object\n var W = [];\n\n /**\n * SHA-1 hash algorithm.\n */\n var SHA1 = C_algo.SHA1 = Hasher.extend({\n _doReset: function () {\n this._hash = new WordArray.init([\n 0x67452301, 0xefcdab89,\n 0x98badcfe, 0x10325476,\n 0xc3d2e1f0\n ]);\n },\n\n _doProcessBlock: function (M, offset) {\n // Shortcut\n var H = this._hash.words;\n\n // Working variables\n var a = H[0];\n var b = H[1];\n var c = H[2];\n var d = H[3];\n var e = H[4];\n\n // Computation\n for (var i = 0; i < 80; i++) {\n if (i < 16) {\n W[i] = M[offset + i] | 0;\n } else {\n var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];\n W[i] = (n << 1) | (n >>> 31);\n }\n\n var t = ((a << 5) | (a >>> 27)) + e + W[i];\n if (i < 20) {\n t += ((b & c) | (~b & d)) + 0x5a827999;\n } else if (i < 40) {\n t += (b ^ c ^ d) + 0x6ed9eba1;\n } else if (i < 60) {\n t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;\n } else /* if (i < 80) */ {\n t += (b ^ c ^ d) - 0x359d3e2a;\n }\n\n e = d;\n d = c;\n c = (b << 30) | (b >>> 2);\n b = a;\n a = t;\n }\n\n // Intermediate hash value\n H[0] = (H[0] + a) | 0;\n H[1] = (H[1] + b) | 0;\n H[2] = (H[2] + c) | 0;\n H[3] = (H[3] + d) | 0;\n H[4] = (H[4] + e) | 0;\n },\n\n _doFinalize: function () {\n // Shortcuts\n var data = this._data;\n var dataWords = data.words;\n\n var nBitsTotal = this._nDataBytes * 8;\n var nBitsLeft = data.sigBytes * 8;\n\n // Add padding\n dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\n data.sigBytes = dataWords.length * 4;\n\n // Hash final blocks\n this._process();\n\n // Return final computed hash\n return this._hash;\n },\n\n clone: function () {\n var clone = Hasher.clone.call(this);\n clone._hash = this._hash.clone();\n\n return clone;\n }\n });\n\n /**\n * Shortcut function to the hasher's object interface.\n *\n * @param {WordArray|string} message The message to hash.\n *\n * @return {WordArray} The hash.\n *\n * @static\n *\n * @example\n *\n * var hash = CryptoJS.SHA1('message');\n * var hash = CryptoJS.SHA1(wordArray);\n */\n C.SHA1 = Hasher._createHelper(SHA1);\n\n /**\n * Shortcut function to the HMAC's object interface.\n *\n * @param {WordArray|string} message The message to hash.\n * @param {WordArray|string} key The secret key.\n *\n * @return {WordArray} The HMAC.\n *\n * @static\n *\n * @example\n *\n * var hmac = CryptoJS.HmacSHA1(message, key);\n */\n C.HmacSHA1 = Hasher._createHmacHelper(SHA1);\n}());\n","/*\r\nCryptoJS v3.1.2\r\ncode.google.com/p/crypto-js\r\n(c) 2009-2013 by Jeff Mott. All rights reserved.\r\ncode.google.com/p/crypto-js/wiki/License\r\n*/\r\n(function (Math) {\r\n // Shortcuts\r\n var C = qq.CryptoJS;\r\n var C_lib = C.lib;\r\n var WordArray = C_lib.WordArray;\r\n var Hasher = C_lib.Hasher;\r\n var C_algo = C.algo;\r\n\r\n // Initialization and round constants tables\r\n var H = [];\r\n var K = [];\r\n\r\n // Compute constants\r\n (function () {\r\n function isPrime(n) {\r\n var sqrtN = Math.sqrt(n);\r\n for (var factor = 2; factor <= sqrtN; factor++) {\r\n if (!(n % factor)) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n function getFractionalBits(n) {\r\n return ((n - (n | 0)) * 0x100000000) | 0;\r\n }\r\n\r\n var n = 2;\r\n var nPrime = 0;\r\n while (nPrime < 64) {\r\n if (isPrime(n)) {\r\n if (nPrime < 8) {\r\n H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));\r\n }\r\n K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));\r\n\r\n nPrime++;\r\n }\r\n\r\n n++;\r\n }\r\n }());\r\n\r\n // Reusable object\r\n var W = [];\r\n\r\n /**\r\n * SHA-256 hash algorithm.\r\n */\r\n var SHA256 = C_algo.SHA256 = Hasher.extend({\r\n _doReset: function () {\r\n this._hash = new WordArray.init(H.slice(0));\r\n },\r\n\r\n _doProcessBlock: function (M, offset) {\r\n // Shortcut\r\n var H = this._hash.words;\r\n\r\n // Working variables\r\n var a = H[0];\r\n var b = H[1];\r\n var c = H[2];\r\n var d = H[3];\r\n var e = H[4];\r\n var f = H[5];\r\n var g = H[6];\r\n var h = H[7];\r\n\r\n // Computation\r\n for (var i = 0; i < 64; i++) {\r\n if (i < 16) {\r\n W[i] = M[offset + i] | 0;\r\n } else {\r\n var gamma0x = W[i - 15];\r\n var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^\r\n ((gamma0x << 14) | (gamma0x >>> 18)) ^\r\n (gamma0x >>> 3);\r\n\r\n var gamma1x = W[i - 2];\r\n var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^\r\n ((gamma1x << 13) | (gamma1x >>> 19)) ^\r\n (gamma1x >>> 10);\r\n\r\n W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];\r\n }\r\n\r\n var ch = (e & f) ^ (~e & g);\r\n var maj = (a & b) ^ (a & c) ^ (b & c);\r\n\r\n var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));\r\n var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25));\r\n\r\n var t1 = h + sigma1 + ch + K[i] + W[i];\r\n var t2 = sigma0 + maj;\r\n\r\n h = g;\r\n g = f;\r\n f = e;\r\n e = (d + t1) | 0;\r\n d = c;\r\n c = b;\r\n b = a;\r\n a = (t1 + t2) | 0;\r\n }\r\n\r\n // Intermediate hash value\r\n H[0] = (H[0] + a) | 0;\r\n H[1] = (H[1] + b) | 0;\r\n H[2] = (H[2] + c) | 0;\r\n H[3] = (H[3] + d) | 0;\r\n H[4] = (H[4] + e) | 0;\r\n H[5] = (H[5] + f) | 0;\r\n H[6] = (H[6] + g) | 0;\r\n H[7] = (H[7] + h) | 0;\r\n },\r\n\r\n _doFinalize: function () {\r\n // Shortcuts\r\n var data = this._data;\r\n var dataWords = data.words;\r\n\r\n var nBitsTotal = this._nDataBytes * 8;\r\n var nBitsLeft = data.sigBytes * 8;\r\n\r\n // Add padding\r\n dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\r\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\r\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\r\n data.sigBytes = dataWords.length * 4;\r\n\r\n // Hash final blocks\r\n this._process();\r\n\r\n // Return final computed hash\r\n return this._hash;\r\n },\r\n\r\n clone: function () {\r\n var clone = Hasher.clone.call(this);\r\n clone._hash = this._hash.clone();\r\n\r\n return clone;\r\n }\r\n });\r\n\r\n /**\r\n * Shortcut function to the hasher's object interface.\r\n *\r\n * @param {WordArray|string} message The message to hash.\r\n *\r\n * @return {WordArray} The hash.\r\n *\r\n * @static\r\n *\r\n * @example\r\n *\r\n * var hash = CryptoJS.SHA256('message');\r\n * var hash = CryptoJS.SHA256(wordArray);\r\n */\r\n C.SHA256 = Hasher._createHelper(SHA256);\r\n\r\n /**\r\n * Shortcut function to the HMAC's object interface.\r\n *\r\n * @param {WordArray|string} message The message to hash.\r\n * @param {WordArray|string} key The secret key.\r\n *\r\n * @return {WordArray} The HMAC.\r\n *\r\n * @static\r\n *\r\n * @example\r\n *\r\n * var hmac = CryptoJS.HmacSHA256(message, key);\r\n */\r\n C.HmacSHA256 = Hasher._createHmacHelper(SHA256);\r\n}(Math));\r\n","/*\r\nCryptoJS v3.1.2\r\ncode.google.com/p/crypto-js\r\n(c) 2009-2013 by Jeff Mott. All rights reserved.\r\ncode.google.com/p/crypto-js/wiki/License\r\n*/\r\n(function () {\r\n // Check if typed arrays are supported\r\n if (typeof ArrayBuffer != 'function') {\r\n return;\r\n }\r\n\r\n // Shortcuts\r\n var C = qq.CryptoJS;\r\n var C_lib = C.lib;\r\n var WordArray = C_lib.WordArray;\r\n\r\n // Reference original init\r\n var superInit = WordArray.init;\r\n\r\n // Augment WordArray.init to handle typed arrays\r\n var subInit = WordArray.init = function (typedArray) {\r\n // Convert buffers to uint8\r\n if (typedArray instanceof ArrayBuffer) {\r\n typedArray = new Uint8Array(typedArray);\r\n }\r\n\r\n // Convert other array views to uint8\r\n if (\r\n typedArray instanceof Int8Array ||\r\n typedArray instanceof Uint8ClampedArray ||\r\n typedArray instanceof Int16Array ||\r\n typedArray instanceof Uint16Array ||\r\n typedArray instanceof Int32Array ||\r\n typedArray instanceof Uint32Array ||\r\n typedArray instanceof Float32Array ||\r\n typedArray instanceof Float64Array\r\n ) {\r\n typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);\r\n }\r\n\r\n // Handle Uint8Array\r\n if (typedArray instanceof Uint8Array) {\r\n // Shortcut\r\n var typedArrayByteLength = typedArray.byteLength;\r\n\r\n // Extract bytes\r\n var words = [];\r\n for (var i = 0; i < typedArrayByteLength; i++) {\r\n words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8);\r\n }\r\n\r\n // Initialize this word array\r\n superInit.call(this, words, typedArrayByteLength);\r\n } else {\r\n // Else call normal init\r\n superInit.apply(this, arguments);\r\n }\r\n };\r\n\r\n subInit.prototype = WordArray;\r\n}());\r\n","/*globals qq */\nqq.s3 = qq.s3 || {};\n\nqq.s3.util = qq.s3.util || (function() {\n \"use strict\";\n\n return {\n ALGORITHM_PARAM_NAME: \"x-amz-algorithm\",\n\n AWS_PARAM_PREFIX: \"x-amz-meta-\",\n\n CREDENTIAL_PARAM_NAME: \"x-amz-credential\",\n\n DATE_PARAM_NAME: \"x-amz-date\",\n\n REDUCED_REDUNDANCY_PARAM_NAME: \"x-amz-storage-class\",\n REDUCED_REDUNDANCY_PARAM_VALUE: \"REDUCED_REDUNDANCY\",\n\n SERVER_SIDE_ENCRYPTION_PARAM_NAME: \"x-amz-server-side-encryption\",\n SERVER_SIDE_ENCRYPTION_PARAM_VALUE: \"AES256\",\n\n SESSION_TOKEN_PARAM_NAME: \"x-amz-security-token\",\n\n V4_ALGORITHM_PARAM_VALUE: \"AWS4-HMAC-SHA256\",\n\n V4_SIGNATURE_PARAM_NAME: \"x-amz-signature\",\n\n CASE_SENSITIVE_PARAM_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\"\n ],\n\n UNSIGNABLE_REST_HEADER_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\"\n ],\n\n UNPREFIXED_PARAM_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\",\n \"x-amz-server-side-encryption-customer-algorithm\",\n \"x-amz-server-side-encryption-customer-key\",\n \"x-amz-server-side-encryption-customer-key-MD5\"\n ],\n\n /**\n * This allows for the region to be specified in the bucket's endpoint URL, or not.\n *\n * Examples of some valid endpoints are:\n * http://foo.s3.amazonaws.com\n * https://foo.s3.amazonaws.com\n * http://foo.s3-ap-northeast-1.amazonaws.com\n * foo.s3.amazonaws.com\n * http://foo.bar.com\n * http://s3.amazonaws.com/foo.bar.com\n * ...etc\n *\n * @param endpoint The bucket's URL.\n * @returns {String || undefined} The bucket name, or undefined if the URL cannot be parsed.\n */\n getBucket: function(endpoint) {\n var patterns = [\n //bucket in domain\n /^(?:https?:\\/\\/)?([a-z0-9.\\-_]+)\\.s3(?:-[a-z0-9\\-]+)?\\.amazonaws\\.com/i,\n //bucket in path\n /^(?:https?:\\/\\/)?s3(?:-[a-z0-9\\-]+)?\\.amazonaws\\.com\\/([a-z0-9.\\-_]+)/i,\n //custom domain\n /^(?:https?:\\/\\/)?([a-z0-9.\\-_]+)/i\n ],\n bucket;\n\n qq.each(patterns, function(idx, pattern) {\n var match = pattern.exec(endpoint);\n\n if (match) {\n bucket = match[1];\n return false;\n }\n });\n\n return bucket;\n },\n\n /** Create Prefixed request headers which are appropriate for S3.\n *\n * If the request header is appropriate for S3 (e.g. Cache-Control) then pass\n * it along without a metadata prefix. For all other request header parameter names,\n * apply qq.s3.util.AWS_PARAM_PREFIX before the name.\n * See: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html\n */\n _getPrefixedParamName: function(name) {\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {\n return name;\n }\n return qq.s3.util.AWS_PARAM_PREFIX + name;\n },\n\n /**\n * Create a policy document to be signed and sent along with the S3 upload request.\n *\n * @param spec Object with properties use to construct the policy document.\n * @returns {Object} Policy doc.\n */\n getPolicy: function(spec) {\n var policy = {},\n conditions = [],\n bucket = spec.bucket,\n date = spec.date,\n drift = spec.clockDrift,\n key = spec.key,\n accessKey = spec.accessKey,\n acl = spec.acl,\n type = spec.type,\n expectedStatus = spec.expectedStatus,\n sessionToken = spec.sessionToken,\n params = spec.params,\n successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl),\n minFileSize = spec.minFileSize,\n maxFileSize = spec.maxFileSize,\n reducedRedundancy = spec.reducedRedundancy,\n region = spec.region,\n serverSideEncryption = spec.serverSideEncryption,\n signatureVersion = spec.signatureVersion;\n\n policy.expiration = qq.s3.util.getPolicyExpirationDate(date, drift);\n\n conditions.push({acl: acl});\n conditions.push({bucket: bucket});\n\n if (type) {\n conditions.push({\"Content-Type\": type});\n }\n\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (expectedStatus) {\n conditions.push({success_action_status: expectedStatus.toString()});\n }\n\n if (successRedirectUrl) {\n conditions.push({success_action_redirect: successRedirectUrl});\n }\n // jscs:enable\n if (reducedRedundancy) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (sessionToken) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n if (serverSideEncryption) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n if (signatureVersion === 2) {\n conditions.push({key: key});\n }\n else if (signatureVersion === 4) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;\n\n conditions.push({});\n conditions[conditions.length - 1].key = key;\n\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.CREDENTIAL_PARAM_NAME] =\n qq.s3.util.getV4CredentialsString({date: date, key: accessKey, region: region});\n\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.DATE_PARAM_NAME] =\n qq.s3.util.getV4PolicyDate(date, drift);\n }\n\n // user metadata\n qq.each(params, function(name, val) {\n var awsParamName = qq.s3.util._getPrefixedParamName(name),\n param = {};\n\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {\n param[awsParamName] = val;\n }\n else {\n param[awsParamName] = encodeURIComponent(val);\n }\n\n conditions.push(param);\n });\n\n policy.conditions = conditions;\n\n qq.s3.util.enforceSizeLimits(policy, minFileSize, maxFileSize);\n\n return policy;\n },\n\n /**\n * Update a previously constructed policy document with updated credentials. Currently, this only requires we\n * update the session token. This is only relevant if requests are being signed client-side.\n *\n * @param policy Live policy document\n * @param newSessionToken Updated session token.\n */\n refreshPolicyCredentials: function(policy, newSessionToken) {\n var sessionTokenFound = false;\n\n qq.each(policy.conditions, function(oldCondIdx, oldCondObj) {\n qq.each(oldCondObj, function(oldCondName, oldCondVal) {\n if (oldCondName === qq.s3.util.SESSION_TOKEN_PARAM_NAME) {\n oldCondObj[oldCondName] = newSessionToken;\n sessionTokenFound = true;\n }\n });\n });\n\n if (!sessionTokenFound) {\n policy.conditions.push({});\n policy.conditions[policy.conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = newSessionToken;\n }\n },\n\n /**\n * Generates all parameters to be passed along with the S3 upload request. This includes invoking a callback\n * that is expected to asynchronously retrieve a signature for the policy document. Note that the server\n * signing the request should reject a \"tainted\" policy document that includes unexpected values, since it is\n * still possible for a malicious user to tamper with these values during policy document generation,\n * before it is sent to the server for signing.\n *\n * @param spec Object with properties: `params`, `type`, `key`, `accessKey`, `acl`, `expectedStatus`, `successRedirectUrl`,\n * `reducedRedundancy`, `region`, `serverSideEncryption`, `version`, and `log()`, along with any options associated with `qq.s3.util.getPolicy()`.\n * @returns {qq.Promise} Promise that will be fulfilled once all parameters have been determined.\n */\n generateAwsParams: function(spec, signPolicyCallback) {\n var awsParams = {},\n customParams = spec.params,\n promise = new qq.Promise(),\n sessionToken = spec.sessionToken,\n drift = spec.clockDrift,\n type = spec.type,\n key = spec.key,\n accessKey = spec.accessKey,\n acl = spec.acl,\n expectedStatus = spec.expectedStatus,\n successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl),\n reducedRedundancy = spec.reducedRedundancy,\n region = spec.region,\n serverSideEncryption = spec.serverSideEncryption,\n signatureVersion = spec.signatureVersion,\n now = new Date(),\n log = spec.log,\n policyJson;\n\n spec.date = now;\n policyJson = qq.s3.util.getPolicy(spec);\n\n awsParams.key = key;\n\n if (type) {\n awsParams[\"Content-Type\"] = type;\n }\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (expectedStatus) {\n awsParams.success_action_status = expectedStatus;\n }\n\n if (successRedirectUrl) {\n awsParams.success_action_redirect = successRedirectUrl;\n }\n // jscs:enable\n if (reducedRedundancy) {\n awsParams[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (serverSideEncryption) {\n awsParams[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n if (sessionToken) {\n awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n awsParams.acl = acl;\n\n // Custom (user-supplied) params must be prefixed with the value of `qq.s3.util.AWS_PARAM_PREFIX`.\n // Params such as Cache-Control or Content-Disposition will not be prefixed.\n // Prefixed param values will be URI encoded as well.\n qq.each(customParams, function(name, val) {\n var awsParamName = qq.s3.util._getPrefixedParamName(name);\n\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {\n awsParams[awsParamName] = val;\n }\n else {\n awsParams[awsParamName] = encodeURIComponent(val);\n }\n });\n\n if (signatureVersion === 2) {\n awsParams.AWSAccessKeyId = accessKey;\n }\n else if (signatureVersion === 4) {\n awsParams[qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;\n awsParams[qq.s3.util.CREDENTIAL_PARAM_NAME] = qq.s3.util.getV4CredentialsString({date: now, key: accessKey, region: region});\n awsParams[qq.s3.util.DATE_PARAM_NAME] = qq.s3.util.getV4PolicyDate(now, drift);\n }\n\n // Invoke a promissory callback that should provide us with a base64-encoded policy doc and an\n // HMAC signature for the policy doc.\n signPolicyCallback(policyJson).then(\n function(policyAndSignature, updatedAccessKey, updatedSessionToken) {\n awsParams.policy = policyAndSignature.policy;\n\n if (spec.signatureVersion === 2) {\n awsParams.signature = policyAndSignature.signature;\n\n if (updatedAccessKey) {\n awsParams.AWSAccessKeyId = updatedAccessKey;\n }\n }\n else if (spec.signatureVersion === 4) {\n awsParams[qq.s3.util.V4_SIGNATURE_PARAM_NAME] = policyAndSignature.signature;\n }\n\n if (updatedSessionToken) {\n awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;\n }\n\n promise.success(awsParams);\n },\n function(errorMessage) {\n errorMessage = errorMessage || \"Can't continue further with request to S3 as we did not receive \" +\n \"a valid signature and policy from the server.\";\n\n log(\"Policy signing failed. \" + errorMessage, \"error\");\n promise.failure(errorMessage);\n }\n );\n\n return promise;\n },\n\n /**\n * Add a condition to an existing S3 upload request policy document used to ensure AWS enforces any size\n * restrictions placed on files server-side. This is important to do, in case users mess with the client-side\n * checks already in place.\n *\n * @param policy Policy document as an `Object`, with a `conditions` property already attached\n * @param minSize Minimum acceptable size, in bytes\n * @param maxSize Maximum acceptable size, in bytes (0 = unlimited)\n */\n enforceSizeLimits: function(policy, minSize, maxSize) {\n var adjustedMinSize = minSize < 0 ? 0 : minSize,\n // Adjust a maxSize of 0 to the largest possible integer, since we must specify a high and a low in the request\n adjustedMaxSize = maxSize <= 0 ? 9007199254740992 : maxSize;\n\n if (minSize > 0 || maxSize > 0) {\n policy.conditions.push([\"content-length-range\", adjustedMinSize.toString(), adjustedMaxSize.toString()]);\n }\n },\n\n getPolicyExpirationDate: function(date, drift) {\n var adjustedDate = new Date(date.getTime() + drift);\n return qq.s3.util.getPolicyDate(adjustedDate, 5);\n },\n\n getCredentialsDate: function(date) {\n return date.getUTCFullYear() + \"\" +\n (\"0\" + (date.getUTCMonth() + 1)).slice(-2) +\n (\"0\" + date.getUTCDate()).slice(-2);\n },\n\n getPolicyDate: function(date, _minutesToAdd_) {\n var minutesToAdd = _minutesToAdd_ || 0,\n pad, r;\n\n /*jshint -W014 */\n // Is this going to be a problem if we encounter this moments before 2 AM just before daylight savings time ends?\n date.setMinutes(date.getMinutes() + (minutesToAdd || 0));\n\n if (Date.prototype.toISOString) {\n return date.toISOString();\n }\n else {\n pad = function(number) {\n r = String(number);\n\n if (r.length === 1) {\n r = \"0\" + r;\n }\n\n return r;\n };\n\n return date.getUTCFullYear()\n + \"-\" + pad(date.getUTCMonth() + 1)\n + \"-\" + pad(date.getUTCDate())\n + \"T\" + pad(date.getUTCHours())\n + \":\" + pad(date.getUTCMinutes())\n + \":\" + pad(date.getUTCSeconds())\n + \".\" + String((date.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)\n + \"Z\";\n }\n },\n\n /**\n * Looks at a response from S3 contained in an iframe and parses the query string in an attempt to identify\n * the associated resource.\n *\n * @param iframe Iframe containing response\n * @returns {{bucket: *, key: *, etag: *}}\n */\n parseIframeResponse: function(iframe) {\n var doc = iframe.contentDocument || iframe.contentWindow.document,\n queryString = doc.location.search,\n match = /bucket=(.+)&key=(.+)&etag=(.+)/.exec(queryString);\n\n if (match) {\n return {\n bucket: match[1],\n key: match[2],\n etag: match[3].replace(/%22/g, \"\")\n };\n }\n },\n\n /**\n * @param successRedirectUrl Relative or absolute location of success redirect page\n * @returns {*|string} undefined if the parameter is undefined, otherwise the absolute location of the success redirect page\n */\n getSuccessRedirectAbsoluteUrl: function(successRedirectUrl) {\n if (successRedirectUrl) {\n var targetAnchorContainer = document.createElement(\"div\"),\n targetAnchor;\n\n if (qq.ie7()) {\n // Note that we must make use of `innerHTML` for IE7 only instead of simply creating an anchor via\n // `document.createElement('a')` and setting the `href` attribute. The latter approach does not allow us to\n // obtain an absolute URL in IE7 if the `endpoint` is a relative URL.\n targetAnchorContainer.innerHTML = \" \";\n targetAnchor = targetAnchorContainer.firstChild;\n return targetAnchor.href;\n }\n else {\n // IE8 and IE9 do not seem to derive an absolute URL from a relative URL using the `innerHTML`\n // approach above, so we'll just create an anchor this way and set it's `href` attribute.\n // Due to yet another quirk in IE8 and IE9, we have to set the `href` equal to itself\n // in order to ensure relative URLs will be properly parsed.\n targetAnchor = document.createElement(\"a\");\n targetAnchor.href = successRedirectUrl;\n targetAnchor.href = targetAnchor.href;\n return targetAnchor.href;\n }\n }\n },\n\n getV4CredentialsString: function(spec) {\n return spec.key + \"/\" +\n qq.s3.util.getCredentialsDate(spec.date) + \"/\" +\n spec.region + \"/s3/aws4_request\";\n },\n\n getV4PolicyDate: function(date, drift) {\n var adjustedDate = new Date(date.getTime() + drift);\n\n return qq.s3.util.getCredentialsDate(adjustedDate) + \"T\" +\n (\"0\" + adjustedDate.getUTCHours()).slice(-2) +\n (\"0\" + adjustedDate.getUTCMinutes()).slice(-2) +\n (\"0\" + adjustedDate.getUTCSeconds()).slice(-2) +\n \"Z\";\n },\n\n // AWS employs a strict interpretation of [RFC 3986](http://tools.ietf.org/html/rfc3986#page-12).\n // So, we must ensure all reserved characters listed in the spec are percent-encoded,\n // and spaces are replaced with \"+\".\n encodeQueryStringParam: function(param) {\n var percentEncoded = encodeURIComponent(param);\n\n // %-encode characters not handled by `encodeURIComponent` (to follow RFC 3986)\n percentEncoded = percentEncoded.replace(/[!'()]/g, escape);\n\n // %-encode characters not handled by `escape` (to follow RFC 3986)\n percentEncoded = percentEncoded.replace(/\\*/g, \"%2A\");\n\n // replace percent-encoded spaces with a \"+\"\n return percentEncoded.replace(/%20/g, \"+\");\n },\n /**\n * Escapes url part as for AWS requirements\n * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js\n */\n uriEscape: function(string) {\n var output = encodeURIComponent(string);\n output = output.replace(/[^A-Za-z0-9_.~\\-%]+/g, escape);\n output = output.replace(/[*]/g, function(ch) {\n return \"%\" + ch.charCodeAt(0).toString(16).toUpperCase();\n });\n return output;\n },\n /**\n * Escapes a path as for AWS requirement\n * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js\n */\n uriEscapePath: function(path) {\n var parts = [];\n qq.each(path.split(\"/\"), function(idx, item) {\n parts.push(qq.s3.util.uriEscape(item));\n });\n return parts.join(\"/\");\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to S3, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to S3.\n * Some inherited options and API methods have a special meaning in the context of the S3 uploader.\n */\n(function() {\n \"use strict\";\n\n qq.s3.FineUploaderBasic = function(o) {\n var options = {\n request: {\n // public key (required for server-side signing, ignored if `credentials` have been provided)\n accessKey: null,\n\n // padding, in milliseconds, to add to the x-amz-date header & the policy expiration date\n clockDrift: 0\n },\n\n objectProperties: {\n acl: \"private\",\n\n // string or a function which may be promissory\n bucket: qq.bind(function(id) {\n return qq.s3.util.getBucket(this.getEndpoint(id));\n }, this),\n\n // string or a function which may be promissory - only used for V4 multipart uploads\n host: qq.bind(function(id) {\n return (/(?:http|https):\\/\\/(.+)(?:\\/.+)?/).exec(this._endpointStore.get(id))[1];\n }, this),\n\n // 'uuid', 'filename', or a function which may be promissory\n key: \"uuid\",\n\n reducedRedundancy: false,\n\n // Defined at http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\n region: \"us-east-1\",\n\n serverSideEncryption: false\n },\n\n credentials: {\n // Public key (required).\n accessKey: null,\n // Private key (required).\n secretKey: null,\n // Expiration date for the credentials (required). May be an ISO string or a `Date`.\n expiration: null,\n // Temporary credentials session token.\n // Only required for temporary credentials obtained via AssumeRoleWithWebIdentity.\n sessionToken: null\n },\n\n // All but `version` are ignored if `credentials` is provided.\n signature: {\n customHeaders: {},\n endpoint: null,\n version: 2\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n // required if non-File-API browsers, such as IE9 and older, are used\n iframeSupport: {\n localBlankPagePath: null\n },\n\n chunking: {\n // minimum part size is 5 MiB when uploading to S3\n partSize: 5242880\n },\n\n cors: {\n allowXdr: true\n },\n\n callbacks: {\n onCredentialsExpired: function() {}\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n if (!this.setCredentials(options.credentials, true)) {\n this._currentCredentials.accessKey = options.request.accessKey;\n }\n\n this._aclStore = this._createStore(options.objectProperties.acl);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds S3 keys for file representations constructed from a session request.\n this._cannedKeys = {};\n // Holds S3 buckets for file representations constructed from a session request.\n this._cannedBuckets = {};\n\n this._buckets = {};\n this._hosts = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.s3.FineUploaderBasic.prototype, {\n getBucket: function(id) {\n if (this._cannedBuckets[id] == null) {\n return this._buckets[id];\n }\n return this._cannedBuckets[id];\n },\n\n /**\n * @param id File ID\n * @returns {*} Key name associated w/ the file, if one exists\n */\n getKey: function(id) {\n /* jshint eqnull:true */\n if (this._cannedKeys[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n\n return this._cannedKeys[id];\n },\n\n /**\n * Override the parent's reset function to cleanup various S3-related items.\n */\n reset: function() {\n qq.FineUploaderBasic.prototype.reset.call(this);\n this._failedSuccessRequestCallbacks = [];\n this._buckets = {};\n this._hosts = {};\n },\n\n setCredentials: function(credentials, ignoreEmpty) {\n if (credentials && credentials.secretKey) {\n if (!credentials.accessKey) {\n throw new qq.Error(\"Invalid credentials: no accessKey\");\n }\n else if (!credentials.expiration) {\n throw new qq.Error(\"Invalid credentials: no expiration\");\n }\n else {\n this._currentCredentials = qq.extend({}, credentials);\n\n // Ensure expiration is a `Date`. If initially a string, assuming it is in ISO format.\n if (qq.isString(credentials.expiration)) {\n this._currentCredentials.expiration = new Date(credentials.expiration);\n }\n }\n\n return true;\n }\n else if (!ignoreEmpty) {\n throw new qq.Error(\"Invalid credentials parameter!\");\n }\n else {\n this._currentCredentials = {};\n }\n },\n\n setAcl: function(acl, id) {\n this._aclStore.set(acl, id);\n },\n\n /**\n * Ensures the parent's upload handler creator passes any additional S3-specific options to the handler as well\n * as information required to instantiate the specific handler based on the current browser's capabilities.\n *\n * @returns {qq.UploadHandlerController}\n * @private\n */\n _createUploadHandler: function() {\n var self = this,\n additionalOptions = {\n aclStore: this._aclStore,\n getBucket: qq.bind(this._determineBucket, this),\n getHost: qq.bind(this._determineHost, this),\n getKeyName: qq.bind(this._determineKeyName, this),\n iframeSupport: this._options.iframeSupport,\n objectProperties: this._options.objectProperties,\n signature: this._options.signature,\n clockDrift: this._options.request.clockDrift,\n // pass size limit validation values to include in the request so AWS enforces this server-side\n validation: {\n minSizeLimit: this._options.validation.minSizeLimit,\n maxSizeLimit: this._options.validation.sizeLimit\n }\n };\n\n // We assume HTTP if it is missing from the start of the endpoint string.\n qq.override(this._endpointStore, function(super_) {\n return {\n get: function(id) {\n var endpoint = super_.get(id);\n\n if (endpoint.indexOf(\"http\") < 0) {\n return \"http://\" + endpoint;\n }\n\n return endpoint;\n }\n };\n });\n\n // Some param names should be lower case to avoid signature mismatches\n qq.override(this._paramsStore, function(super_) {\n return {\n get: function(id) {\n var oldParams = super_.get(id),\n modifiedParams = {};\n\n qq.each(oldParams, function(name, val) {\n var paramName = name;\n\n if (qq.indexOf(qq.s3.util.CASE_SENSITIVE_PARAM_NAMES, paramName) < 0) {\n paramName = paramName.toLowerCase();\n }\n\n modifiedParams[paramName] = qq.isFunction(val) ? val() : val;\n });\n\n return modifiedParams;\n }\n };\n });\n\n additionalOptions.signature.credentialsProvider = {\n get: function() {\n return self._currentCredentials;\n },\n\n onExpired: function() {\n var updateCredentials = new qq.Promise(),\n callbackRetVal = self._options.callbacks.onCredentialsExpired();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n callbackRetVal.then(function(credentials) {\n try {\n self.setCredentials(credentials);\n updateCredentials.success();\n }\n catch (error) {\n self.log(\"Invalid credentials returned from onCredentialsExpired callback! (\" + error.message + \")\", \"error\");\n updateCredentials.failure(\"onCredentialsExpired did not return valid credentials.\");\n }\n }, function(errorMsg) {\n self.log(\"onCredentialsExpired callback indicated failure! (\" + errorMsg + \")\", \"error\");\n updateCredentials.failure(\"onCredentialsExpired callback failed.\");\n });\n }\n else {\n self.log(\"onCredentialsExpired callback did not return a promise!\", \"error\");\n updateCredentials.failure(\"Unexpected return value for onCredentialsExpired.\");\n }\n\n return updateCredentials;\n }\n };\n\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this, additionalOptions, \"s3\");\n },\n\n _determineObjectPropertyValue: function(id, property) {\n var maybe = this._options.objectProperties[property],\n promise = new qq.Promise(),\n self = this;\n\n if (qq.isFunction(maybe)) {\n maybe = maybe(id);\n if (qq.isGenericPromise(maybe)) {\n promise = maybe;\n }\n else {\n promise.success(maybe);\n }\n }\n else if (qq.isString(maybe)) {\n promise.success(maybe);\n }\n\n promise.then(\n function success(value) {\n self[\"_\" + property + \"s\"][id] = value;\n },\n\n function failure(errorMsg) {\n qq.log(\"Problem determining \" + property + \" for ID \" + id + \" (\" + errorMsg + \")\", \"error\");\n }\n );\n\n return promise;\n },\n\n _determineBucket: function(id) {\n return this._determineObjectPropertyValue(id, \"bucket\");\n },\n\n _determineHost: function(id) {\n return this._determineObjectPropertyValue(id, \"host\");\n },\n\n /**\n * Determine the file's key name and passes it to the caller via a promissory callback. This also may\n * delegate to an integrator-defined function that determines the file's key name on demand,\n * which also may be promissory.\n *\n * @param id ID of the file\n * @param filename Name of the file\n * @returns {qq.Promise} A promise that will be fulfilled when the key name has been determined (and will be passed to the caller via the success callback).\n * @private\n */\n _determineKeyName: function(id, filename) {\n /*jshint -W015*/\n var promise = new qq.Promise(),\n keynameLogic = this._options.objectProperties.key,\n extension = qq.getExtension(filename),\n onGetKeynameFailure = promise.failure,\n onGetKeynameSuccess = function(keyname, extension) {\n var keynameToUse = keyname;\n\n if (extension !== undefined) {\n keynameToUse += \".\" + extension;\n }\n\n promise.success(keynameToUse);\n };\n\n switch (keynameLogic) {\n case \"uuid\":\n onGetKeynameSuccess(this.getUuid(id), extension);\n break;\n case \"filename\":\n onGetKeynameSuccess(filename);\n break;\n default:\n if (qq.isFunction(keynameLogic)) {\n this._handleKeynameFunction(keynameLogic, id, onGetKeynameSuccess, onGetKeynameFailure);\n }\n else {\n this.log(keynameLogic + \" is not a valid value for the s3.keyname option!\", \"error\");\n onGetKeynameFailure();\n }\n }\n\n return promise;\n },\n\n /**\n * Called by the internal onUpload handler if the integrator has supplied a function to determine\n * the file's key name. The integrator's function may be promissory. We also need to fulfill\n * the promise contract associated with the caller as well.\n *\n * @param keynameFunc Integrator-supplied function that must be executed to determine the key name. May be promissory.\n * @param id ID of the associated file\n * @param successCallback Invoke this if key name retrieval is successful, passing in the key name.\n * @param failureCallback Invoke this if key name retrieval was unsuccessful.\n * @private\n */\n _handleKeynameFunction: function(keynameFunc, id, successCallback, failureCallback) {\n var self = this,\n onSuccess = function(keyname) {\n successCallback(keyname);\n },\n onFailure = function(reason) {\n self.log(qq.format(\"Failed to retrieve key name for {}. Reason: {}\", id, reason || \"null\"), \"error\");\n failureCallback(reason);\n },\n keyname = keynameFunc.call(this, id);\n\n if (qq.isGenericPromise(keyname)) {\n keyname.then(onSuccess, onFailure);\n }\n /*jshint -W116*/\n else if (keyname == null) {\n onFailure();\n }\n else {\n onSuccess(keyname);\n }\n },\n\n _getEndpointSpecificParams: function(id, response, maybeXhr) {\n var params = {\n key: this.getKey(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n bucket: this.getBucket(id)\n };\n\n if (maybeXhr && maybeXhr.getResponseHeader(\"ETag\")) {\n params.etag = maybeXhr.getResponseHeader(\"ETag\");\n }\n else if (response.etag) {\n params.etag = response.etag;\n }\n\n return params;\n },\n\n // Hooks into the base internal `_onSubmitDelete` to add key and bucket params to the delete file request.\n _onSubmitDelete: function(id, onSuccessCallback) {\n var additionalMandatedParams = {\n key: this.getKey(id),\n bucket: this.getBucket(id)\n };\n\n return qq.FineUploaderBasic.prototype._onSubmitDelete.call(this, id, onSuccessCallback, additionalMandatedParams);\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.s3Key == null) {\n throw new qq.Error(\"Did not find s3Key property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedKeys[id] = sessionData.s3Key;\n this._cannedBuckets[id] = sessionData.s3Bucket;\n }\n\n return id;\n }\n });\n}());\n","/* globals qq, CryptoJS */\n\n// IE 10 does not support Uint8ClampedArray. We don't need it, but CryptoJS attempts to reference it\n// inside a conditional via an instanceof check, which breaks S3 v4 signatures for chunked uploads.\nif (!window.Uint8ClampedArray) {\n window.Uint8ClampedArray = function() {};\n}\n/**\n * Handles signature determination for HTML Form Upload requests and Multipart Uploader requests (via the S3 REST API).\n *\n * If the S3 requests are to be signed server side, this module will send a POST request to the server in an attempt\n * to solicit signatures for various S3-related requests. This module also parses the response and attempts\n * to determine if the effort was successful.\n *\n * If the S3 requests are to be signed client-side, without the help of a server, this module will utilize CryptoJS to\n * sign the requests directly in the browser and send them off to S3.\n *\n * @param o Options associated with all such requests\n * @returns {{getSignature: Function}} API method used to initiate the signature request.\n * @constructor\n */\nqq.s3.RequestSigner = function(o) {\n \"use strict\";\n\n var requester,\n thisSignatureRequester = this,\n pendingSignatures = {},\n options = {\n expectingPolicy: false,\n method: \"POST\",\n signatureSpec: {\n drift: 0,\n credentialsProvider: {},\n endpoint: null,\n customHeaders: {},\n version: 2\n },\n maxConnections: 3,\n endpointStore: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n },\n credentialsProvider,\n\n generateHeaders = function(signatureConstructor, signature, promise) {\n var headers = signatureConstructor.getHeaders();\n\n if (options.signatureSpec.version === 4) {\n headers.Authorization = qq.s3.util.V4_ALGORITHM_PARAM_VALUE +\n \" Credential=\" + options.signatureSpec.credentialsProvider.get().accessKey + \"/\" +\n qq.s3.util.getCredentialsDate(signatureConstructor.getRequestDate()) + \"/\" +\n options.signatureSpec.region + \"/\" +\n \"s3/aws4_request,\" +\n \"SignedHeaders=\" + signatureConstructor.getSignedHeaders() + \",\" +\n \"Signature=\" + signature;\n }\n else {\n headers.Authorization = \"AWS \" + options.signatureSpec.credentialsProvider.get().accessKey + \":\" + signature;\n }\n\n promise.success(headers, signatureConstructor.getEndOfUrl());\n },\n\n v2 = {\n getStringToSign: function(signatureSpec) {\n return qq.format(\"{}\\n{}\\n{}\\n\\n{}/{}/{}\",\n signatureSpec.method,\n signatureSpec.contentMd5 || \"\",\n signatureSpec.contentType || \"\",\n signatureSpec.headersStr || \"\\n\",\n signatureSpec.bucket,\n signatureSpec.endOfUrl);\n },\n\n signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {\n var headersWordArray = qq.CryptoJS.enc.Utf8.parse(headersStr),\n headersHmacSha1 = qq.CryptoJS.HmacSHA1(headersWordArray, credentialsProvider.get().secretKey),\n headersHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(headersHmacSha1);\n\n generateHeaders(signatureConstructor, headersHmacSha1Base64, signatureEffort);\n },\n\n signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var policyStr = JSON.stringify(policy),\n policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr),\n base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray),\n policyHmacSha1 = qq.CryptoJS.HmacSHA1(base64Policy, credentialsProvider.get().secretKey),\n policyHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(policyHmacSha1);\n\n signatureEffort.success({\n policy: base64Policy,\n signature: policyHmacSha1Base64\n }, updatedAccessKey, updatedSessionToken);\n }\n },\n\n v4 = {\n getCanonicalQueryString: function(endOfUri) {\n var queryParamIdx = endOfUri.indexOf(\"?\"),\n canonicalQueryString = \"\",\n encodedQueryParams, encodedQueryParamNames, queryStrings;\n\n if (queryParamIdx >= 0) {\n encodedQueryParams = {};\n queryStrings = endOfUri.substr(queryParamIdx + 1).split(\"&\");\n\n qq.each(queryStrings, function(idx, queryString) {\n var nameAndVal = queryString.split(\"=\"),\n paramVal = nameAndVal[1];\n\n if (paramVal == null) {\n paramVal = \"\";\n }\n\n encodedQueryParams[encodeURIComponent(nameAndVal[0])] = encodeURIComponent(paramVal);\n });\n\n encodedQueryParamNames = Object.keys(encodedQueryParams).sort();\n encodedQueryParamNames.forEach(function(encodedQueryParamName, idx) {\n canonicalQueryString += encodedQueryParamName + \"=\" + encodedQueryParams[encodedQueryParamName];\n if (idx < encodedQueryParamNames.length - 1) {\n canonicalQueryString += \"&\";\n }\n });\n }\n\n return canonicalQueryString;\n },\n\n getCanonicalRequest: function(signatureSpec) {\n return qq.format(\"{}\\n{}\\n{}\\n{}\\n{}\\n{}\",\n signatureSpec.method,\n v4.getCanonicalUri(signatureSpec.endOfUrl),\n v4.getCanonicalQueryString(signatureSpec.endOfUrl),\n signatureSpec.headersStr || \"\\n\",\n v4.getSignedHeaders(signatureSpec.headerNames),\n signatureSpec.hashedContent);\n },\n\n getCanonicalUri: function(endOfUri) {\n var path = endOfUri,\n queryParamIdx = endOfUri.indexOf(\"?\");\n\n if (queryParamIdx > 0) {\n path = endOfUri.substr(0, queryParamIdx);\n }\n return \"/\" + path;\n },\n\n getEncodedHashedPayload: function(body) {\n var promise = new qq.Promise(),\n reader;\n\n if (qq.isBlob(body)) {\n // TODO hash blob in webworker if this becomes a notable perf issue\n reader = new FileReader();\n reader.onloadend = function(e) {\n if (e.target.readyState === FileReader.DONE) {\n if (e.target.error) {\n promise.failure(e.target.error);\n }\n else {\n var wordArray = qq.CryptoJS.lib.WordArray.create(e.target.result);\n promise.success(qq.CryptoJS.SHA256(wordArray).toString());\n }\n }\n };\n reader.readAsArrayBuffer(body);\n }\n else {\n body = body || \"\";\n promise.success(qq.CryptoJS.SHA256(body).toString());\n }\n\n return promise;\n },\n\n getScope: function(date, region) {\n return qq.s3.util.getCredentialsDate(date) + \"/\" +\n region + \"/s3/aws4_request\";\n },\n\n getStringToSign: function(signatureSpec) {\n var canonicalRequest = v4.getCanonicalRequest(signatureSpec),\n date = qq.s3.util.getV4PolicyDate(signatureSpec.date, signatureSpec.drift),\n hashedRequest = qq.CryptoJS.SHA256(canonicalRequest).toString(),\n scope = v4.getScope(signatureSpec.date, options.signatureSpec.region),\n stringToSignTemplate = \"AWS4-HMAC-SHA256\\n{}\\n{}\\n{}\";\n\n return {\n hashed: qq.format(stringToSignTemplate, date, scope, hashedRequest),\n raw: qq.format(stringToSignTemplate, date, scope, canonicalRequest)\n };\n },\n\n getSignedHeaders: function(headerNames) {\n var signedHeaders = \"\";\n\n headerNames.forEach(function(headerName, idx) {\n signedHeaders += headerName.toLowerCase();\n\n if (idx < headerNames.length - 1) {\n signedHeaders += \";\";\n }\n });\n\n return signedHeaders;\n },\n\n signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {\n var secretKey = credentialsProvider.get().secretKey,\n headersPattern = /.+\\n.+\\n(\\d+)\\/(.+)\\/s3\\/.+\\n(.+)/,\n matches = headersPattern.exec(headersStr),\n dateKey, dateRegionKey, dateRegionServiceKey, signingKey;\n\n dateKey = qq.CryptoJS.HmacSHA256(matches[1], \"AWS4\" + secretKey);\n dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);\n dateRegionServiceKey = qq.CryptoJS.HmacSHA256(\"s3\", dateRegionKey);\n signingKey = qq.CryptoJS.HmacSHA256(\"aws4_request\", dateRegionServiceKey);\n\n generateHeaders(signatureConstructor, qq.CryptoJS.HmacSHA256(headersStr, signingKey), signatureEffort);\n },\n\n signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var policyStr = JSON.stringify(policy),\n policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr),\n base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray),\n secretKey = credentialsProvider.get().secretKey,\n credentialPattern = /.+\\/(.+)\\/(.+)\\/s3\\/aws4_request/,\n credentialCondition = (function() {\n var credential = null;\n qq.each(policy.conditions, function(key, condition) {\n var val = condition[\"x-amz-credential\"];\n if (val) {\n credential = val;\n return false;\n }\n });\n return credential;\n }()),\n matches, dateKey, dateRegionKey, dateRegionServiceKey, signingKey;\n\n matches = credentialPattern.exec(credentialCondition);\n dateKey = qq.CryptoJS.HmacSHA256(matches[1], \"AWS4\" + secretKey);\n dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);\n dateRegionServiceKey = qq.CryptoJS.HmacSHA256(\"s3\", dateRegionKey);\n signingKey = qq.CryptoJS.HmacSHA256(\"aws4_request\", dateRegionServiceKey);\n\n signatureEffort.success({\n policy: base64Policy,\n signature: qq.CryptoJS.HmacSHA256(base64Policy, signingKey).toString()\n }, updatedAccessKey, updatedSessionToken);\n }\n };\n\n qq.extend(options, o, true);\n credentialsProvider = options.signatureSpec.credentialsProvider;\n\n function handleSignatureReceived(id, xhrOrXdr, isError) {\n var responseJson = xhrOrXdr.responseText,\n pendingSignatureData = pendingSignatures[id],\n promise = pendingSignatureData.promise,\n signatureConstructor = pendingSignatureData.signatureConstructor,\n errorMessage, response;\n\n delete pendingSignatures[id];\n\n // Attempt to parse what we would expect to be a JSON response\n if (responseJson) {\n try {\n response = qq.parseJson(responseJson);\n }\n catch (error) {\n options.log(\"Error attempting to parse signature response: \" + error, \"error\");\n }\n }\n\n // If the response is parsable and contains an `error` property, use it as the error message\n if (response && response.error) {\n isError = true;\n errorMessage = response.error;\n }\n // If we have received a parsable response, and it has an `invalid` property,\n // the policy document or request headers may have been tampered with client-side.\n else if (response && response.invalid) {\n isError = true;\n errorMessage = \"Invalid policy document or request headers!\";\n }\n // Make sure the response contains policy & signature properties\n else if (response) {\n if (options.expectingPolicy && !response.policy) {\n isError = true;\n errorMessage = \"Response does not include the base64 encoded policy!\";\n }\n else if (!response.signature) {\n isError = true;\n errorMessage = \"Response does not include the signature!\";\n }\n }\n // Something unknown went wrong\n else {\n isError = true;\n errorMessage = \"Received an empty or invalid response from the server!\";\n }\n\n if (isError) {\n if (errorMessage) {\n options.log(errorMessage, \"error\");\n }\n\n promise.failure(errorMessage);\n }\n else if (signatureConstructor) {\n generateHeaders(signatureConstructor, response.signature, promise);\n }\n else {\n promise.success(response);\n }\n }\n\n function getStringToSignArtifacts(id, version, requestInfo) {\n var promise = new qq.Promise(),\n method = \"POST\",\n headerNames = [],\n headersStr = \"\",\n now = new Date(),\n endOfUrl, signatureSpec, toSign,\n\n generateStringToSign = function(requestInfo) {\n var contentMd5,\n headerIndexesToRemove = [];\n\n qq.each(requestInfo.headers, function(name) {\n headerNames.push(name);\n });\n headerNames.sort();\n\n qq.each(headerNames, function(idx, headerName) {\n if (qq.indexOf(qq.s3.util.UNSIGNABLE_REST_HEADER_NAMES, headerName) < 0) {\n headersStr += headerName.toLowerCase() + \":\" + requestInfo.headers[headerName].trim() + \"\\n\";\n }\n else if (headerName === \"Content-MD5\") {\n contentMd5 = requestInfo.headers[headerName];\n }\n else {\n headerIndexesToRemove.unshift(idx);\n }\n });\n\n qq.each(headerIndexesToRemove, function(idx, headerIdx) {\n headerNames.splice(headerIdx, 1);\n });\n\n signatureSpec = {\n bucket: requestInfo.bucket,\n contentMd5: contentMd5,\n contentType: requestInfo.contentType,\n date: now,\n drift: options.signatureSpec.drift,\n endOfUrl: endOfUrl,\n hashedContent: requestInfo.hashedContent,\n headerNames: headerNames,\n headersStr: headersStr,\n method: method\n };\n\n toSign = version === 2 ? v2.getStringToSign(signatureSpec) : v4.getStringToSign(signatureSpec);\n\n return {\n date: now,\n endOfUrl: endOfUrl,\n signedHeaders: version === 4 ? v4.getSignedHeaders(signatureSpec.headerNames) : null,\n toSign: version === 4 ? toSign.hashed : toSign,\n toSignRaw: version === 4 ? toSign.raw : toSign\n };\n };\n\n /*jshint indent:false */\n switch (requestInfo.type) {\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_ABORT:\n method = \"DELETE\";\n endOfUrl = qq.format(\"uploadId={}\", requestInfo.uploadId);\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_INITIATE:\n endOfUrl = \"uploads\";\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_COMPLETE:\n endOfUrl = qq.format(\"uploadId={}\", requestInfo.uploadId);\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_UPLOAD:\n method = \"PUT\";\n endOfUrl = qq.format(\"partNumber={}&uploadId={}\", requestInfo.partNum, requestInfo.uploadId);\n break;\n }\n\n endOfUrl = requestInfo.key + \"?\" + endOfUrl;\n\n if (version === 4) {\n v4.getEncodedHashedPayload(requestInfo.content).then(function(hashedContent) {\n requestInfo.headers[\"x-amz-content-sha256\"] = hashedContent;\n requestInfo.headers.Host = requestInfo.host;\n requestInfo.headers[\"x-amz-date\"] = qq.s3.util.getV4PolicyDate(now, options.signatureSpec.drift);\n requestInfo.hashedContent = hashedContent;\n\n promise.success(generateStringToSign(requestInfo));\n }, function (err) {\n promise.failure(err);\n });\n }\n else {\n promise.success(generateStringToSign(requestInfo));\n }\n\n return promise;\n }\n\n function determineSignatureClientSide(id, toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var updatedHeaders;\n\n // REST API request\n if (toBeSigned.signatureConstructor) {\n if (updatedSessionToken) {\n updatedHeaders = toBeSigned.signatureConstructor.getHeaders();\n updatedHeaders[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;\n toBeSigned.signatureConstructor.withHeaders(updatedHeaders);\n }\n\n toBeSigned.signatureConstructor.getToSign(id).then(function(signatureArtifacts) {\n signApiRequest(toBeSigned.signatureConstructor, signatureArtifacts.stringToSign, signatureEffort);\n }, function (err) {\n signatureEffort.failure(err);\n });\n }\n // Form upload (w/ policy document)\n else {\n updatedSessionToken && qq.s3.util.refreshPolicyCredentials(toBeSigned, updatedSessionToken);\n signPolicy(toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n }\n\n function signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n if (options.signatureSpec.version === 4) {\n v4.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n else {\n v2.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n }\n\n function signApiRequest(signatureConstructor, headersStr, signatureEffort) {\n if (options.signatureSpec.version === 4) {\n v4.signApiRequest(signatureConstructor, headersStr, signatureEffort);\n }\n else {\n v2.signApiRequest(signatureConstructor, headersStr, signatureEffort);\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n contentType: \"application/json; charset=utf-8\",\n endpointStore: {\n get: function() {\n return options.signatureSpec.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.signatureSpec.customHeaders,\n log: options.log,\n onComplete: handleSignatureReceived,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * On success, an object containing the parsed JSON response will be passed into the success handler if the\n * request succeeds. Otherwise an error message will be passed into the failure method.\n *\n * @param id File ID.\n * @param toBeSigned an Object that holds the item(s) to be signed\n * @returns {qq.Promise} A promise that is fulfilled when the response has been received.\n */\n getSignature: function(id, toBeSigned) {\n var params = toBeSigned,\n signatureConstructor = toBeSigned.signatureConstructor,\n signatureEffort = new qq.Promise(),\n queryParams;\n\n if (options.signatureSpec.version === 4) {\n queryParams = {v4: true};\n }\n\n if (credentialsProvider.get().secretKey && qq.CryptoJS) {\n if (credentialsProvider.get().expiration.getTime() > Date.now()) {\n determineSignatureClientSide(id, toBeSigned, signatureEffort);\n }\n // If credentials are expired, ask for new ones before attempting to sign request\n else {\n credentialsProvider.onExpired().then(function() {\n determineSignatureClientSide(id, toBeSigned,\n signatureEffort,\n credentialsProvider.get().accessKey,\n credentialsProvider.get().sessionToken);\n }, function(errorMsg) {\n options.log(\"Attempt to update expired credentials apparently failed! Unable to sign request. \", \"error\");\n signatureEffort.failure(\"Unable to sign request - expired credentials.\");\n });\n }\n }\n else {\n options.log(\"Submitting S3 signature request for \" + id);\n\n if (signatureConstructor) {\n signatureConstructor.getToSign(id).then(function(signatureArtifacts) {\n params = {headers: signatureArtifacts.stringToSignRaw};\n requester.initTransport(id)\n .withParams(params)\n .withQueryParams(queryParams)\n .send();\n }, function (err) {\n options.log(\"Failed to construct signature. \", \"error\");\n signatureEffort.failure(\"Failed to construct signature.\");\n });\n }\n else {\n requester.initTransport(id)\n .withParams(params)\n .withQueryParams(queryParams)\n .send();\n }\n\n pendingSignatures[id] = {\n promise: signatureEffort,\n signatureConstructor: signatureConstructor\n };\n }\n\n return signatureEffort;\n },\n\n constructStringToSign: function(type, bucket, host, key) {\n var headers = {},\n uploadId, content, contentType, partNum, artifacts;\n\n return {\n withHeaders: function(theHeaders) {\n headers = theHeaders;\n return this;\n },\n\n withUploadId: function(theUploadId) {\n uploadId = theUploadId;\n return this;\n },\n\n withContent: function(theContent) {\n content = theContent;\n return this;\n },\n\n withContentType: function(theContentType) {\n contentType = theContentType;\n return this;\n },\n\n withPartNum: function(thePartNum) {\n partNum = thePartNum;\n return this;\n },\n\n getToSign: function(id) {\n var sessionToken = credentialsProvider.get().sessionToken,\n promise = new qq.Promise(),\n adjustedDate = new Date(Date.now() + options.signatureSpec.drift);\n\n headers[\"x-amz-date\"] = adjustedDate.toUTCString();\n\n if (sessionToken) {\n headers[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n getStringToSignArtifacts(id, options.signatureSpec.version, {\n bucket: bucket,\n content: content,\n contentType: contentType,\n headers: headers,\n host: host,\n key: key,\n partNum: partNum,\n type: type,\n uploadId: uploadId\n }).then(function(_artifacts_) {\n artifacts = _artifacts_;\n promise.success({\n headers: (function() {\n if (contentType) {\n headers[\"Content-Type\"] = contentType;\n }\n\n delete headers.Host; // we don't want this to be set on the XHR-initiated request\n return headers;\n }()),\n date: artifacts.date,\n endOfUrl: artifacts.endOfUrl,\n signedHeaders: artifacts.signedHeaders,\n stringToSign: artifacts.toSign,\n stringToSignRaw: artifacts.toSignRaw\n });\n }, function (err) {\n promise.failure(err);\n });\n\n return promise;\n },\n\n getHeaders: function() {\n return qq.extend({}, headers);\n },\n\n getEndOfUrl: function() {\n return artifacts && artifacts.endOfUrl;\n },\n\n getRequestDate: function() {\n return artifacts && artifacts.date;\n },\n\n getSignedHeaders: function() {\n return artifacts && artifacts.signedHeaders;\n }\n };\n }\n });\n};\n\nqq.s3.RequestSigner.prototype.REQUEST_TYPE = {\n MULTIPART_INITIATE: \"multipart_initiate\",\n MULTIPART_COMPLETE: \"multipart_complete\",\n MULTIPART_ABORT: \"multipart_abort\",\n MULTIPART_UPLOAD: \"multipart_upload\"\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/*globals qq*/\n/**\n * Ajax requester used to send an [\"Initiate Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadInitiate.html)\n * request to S3 via the REST API.\n *\n * @param o Options from the caller - will override the defaults.\n * @constructor\n */\nqq.s3.InitiateMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingInitiateRequests = {},\n options = {\n filenameParam: \"qqfilename\",\n method: \"POST\",\n endpointStore: null,\n paramsStore: null,\n signatureSpec: null,\n aclStore: null,\n reducedRedundancy: false,\n serverSideEncryption: false,\n maxConnections: 3,\n getContentType: function(id) {},\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n getName: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Determine all headers for the \"Initiate MPU\" request, including the \"Authorization\" header, which must be determined\n * by the local server. This is a promissory function. If the server responds with a signature, the headers\n * (including the Authorization header) will be passed into the success method of the promise. Otherwise, the failure\n * method on the promise will be called.\n *\n * @param id Associated file ID\n * @returns {qq.Promise}\n */\n function getHeaders(id) {\n var bucket = options.getBucket(id),\n host = options.getHost(id),\n headers = {},\n promise = new qq.Promise(),\n key = options.getKey(id),\n signatureConstructor;\n\n headers[\"x-amz-acl\"] = options.aclStore.get(id);\n\n if (options.reducedRedundancy) {\n headers[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (options.serverSideEncryption) {\n headers[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n headers[qq.s3.util.AWS_PARAM_PREFIX + options.filenameParam] = encodeURIComponent(options.getName(id));\n\n qq.each(options.paramsStore.get(id), function(name, val) {\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {\n headers[name] = val;\n }\n else {\n headers[qq.s3.util.AWS_PARAM_PREFIX + name] = encodeURIComponent(val);\n }\n });\n\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_INITIATE, bucket, host, key)\n .withContentType(options.getContentType(id))\n .withHeaders(headers);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Initiate MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleInitiateRequestComplete(id, xhr, isError) {\n var promise = pendingInitiateRequests[id],\n domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n uploadIdElements, messageElements, uploadId, errorMessage, status;\n\n delete pendingInitiateRequests[id];\n\n // The base ajax requester may declare the request to be a failure based on status code.\n if (isError) {\n status = xhr.status;\n\n messageElements = responseDoc.getElementsByTagName(\"Message\");\n if (messageElements.length > 0) {\n errorMessage = messageElements[0].textContent;\n }\n }\n // If the base ajax requester has not declared this a failure, make sure we can retrieve the uploadId from the response.\n else {\n uploadIdElements = responseDoc.getElementsByTagName(\"UploadId\");\n if (uploadIdElements.length > 0) {\n uploadId = uploadIdElements[0].textContent;\n }\n else {\n errorMessage = \"Upload ID missing from request\";\n }\n }\n\n // Either fail the promise (passing a descriptive error message) or declare it a success (passing the upload ID)\n if (uploadId === undefined) {\n if (errorMessage) {\n options.log(qq.format(\"Specific problem detected initiating multipart upload request for {}: '{}'.\", id, errorMessage), \"error\");\n }\n else {\n options.log(qq.format(\"Unexplained error with initiate multipart upload request for {}. Status code {}.\", id, status), \"error\");\n }\n\n promise.failure(\"Problem initiating upload request.\", xhr);\n }\n else {\n options.log(qq.format(\"Initiate multipart upload request successful for {}. Upload ID is {}\", id, uploadId));\n promise.success(uploadId, xhr);\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n method: options.method,\n contentType: null,\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleInitiateRequestComplete,\n successfulResponseCodes: {\n POST: [200]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Initiate MPU\" request to AWS via the REST API. First, though, we must get a signature from the\n * local server for the request. If all is successful, the uploadId from AWS will be passed into the promise's\n * success handler. Otherwise, an error message will ultimately be passed into the failure method.\n *\n * @param id The ID associated with the file\n * @returns {qq.Promise}\n */\n send: function(id) {\n var promise = new qq.Promise();\n\n getHeaders(id).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 initiate multipart upload request for \" + id);\n\n pendingInitiateRequests[id] = promise;\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .send();\n }, promise.failure);\n\n return promise;\n }\n });\n};\n","/*globals qq*/\n/**\n * Ajax requester used to send an [\"Complete Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadComplete.html)\n * request to S3 via the REST API.\n *\n * @param o Options passed by the creator, to overwrite any default option values.\n * @constructor\n */\nqq.s3.CompleteMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingCompleteRequests = {},\n options = {\n method: \"POST\",\n contentType: \"text/xml\",\n endpointStore: null,\n signatureSpec: null,\n maxConnections: 3,\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n // Transport for requesting signatures (for the \"Complete\" requests) from the local server\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Attach all required headers (including Authorization) to the \"Complete\" request. This is a promissory function\n * that will fulfill the associated promise once all headers have been attached or when an error has occurred that\n * prevents headers from being attached.\n *\n * @returns {qq.Promise}\n */\n function getHeaders(id, uploadId, body) {\n var headers = {},\n promise = new qq.Promise(),\n bucket = options.getBucket(id),\n host = options.getHost(id),\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_COMPLETE, bucket, host, options.getKey(id))\n .withUploadId(uploadId)\n .withContent(body)\n .withContentType(\"application/xml; charset=UTF-8\");\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Complete MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleCompleteRequestComplete(id, xhr, isError) {\n var promise = pendingCompleteRequests[id],\n domParser = new DOMParser(),\n bucket = options.getBucket(id),\n key = options.getKey(id),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n bucketEls = responseDoc.getElementsByTagName(\"Bucket\"),\n keyEls = responseDoc.getElementsByTagName(\"Key\");\n\n delete pendingCompleteRequests[id];\n\n options.log(qq.format(\"Complete response status {}, body = {}\", xhr.status, xhr.responseText));\n\n // If the base requester has determine this a failure, give up.\n if (isError) {\n options.log(qq.format(\"Complete Multipart Upload request for {} failed with status {}.\", id, xhr.status), \"error\");\n }\n else {\n // Make sure the correct bucket and key has been specified in the XML response from AWS.\n if (bucketEls.length && keyEls.length) {\n if (bucketEls[0].textContent !== bucket) {\n isError = true;\n options.log(qq.format(\"Wrong bucket in response to Complete Multipart Upload request for {}.\", id), \"error\");\n }\n\n // TODO Compare key name from response w/ expected key name if AWS ever fixes the encoding of key names in this response.\n }\n else {\n isError = true;\n options.log(qq.format(\"Missing bucket and/or key in response to Complete Multipart Upload request for {}.\", id), \"error\");\n }\n }\n\n if (isError) {\n promise.failure(\"Problem combining the file parts!\", xhr);\n }\n else {\n promise.success({}, xhr);\n }\n }\n\n /**\n * @param etagEntries Array of objects containing `etag` values and their associated `part` numbers.\n * @returns {string} XML string containing the body to send with the \"Complete\" request\n */\n function getCompleteRequestBody(etagEntries) {\n var doc = document.implementation.createDocument(null, \"CompleteMultipartUpload\", null);\n\n // The entries MUST be sorted by part number, per the AWS API spec.\n etagEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(etagEntries, function(idx, etagEntry) {\n var part = etagEntry.part,\n etag = etagEntry.etag,\n partEl = doc.createElement(\"Part\"),\n partNumEl = doc.createElement(\"PartNumber\"),\n partNumTextEl = doc.createTextNode(part),\n etagTextEl = doc.createTextNode(etag),\n etagEl = doc.createElement(\"ETag\");\n\n etagEl.appendChild(etagTextEl);\n partNumEl.appendChild(partNumTextEl);\n partEl.appendChild(partNumEl);\n partEl.appendChild(etagEl);\n qq(doc).children()[0].appendChild(partEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n method: options.method,\n contentType: \"application/xml; charset=UTF-8\",\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleCompleteRequestComplete,\n successfulResponseCodes: {\n POST: [200]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Complete\" request and fulfills the returned promise when the success of this request is known.\n *\n * @param id ID associated with the file.\n * @param uploadId AWS uploadId for this file\n * @param etagEntries Array of objects containing `etag` values and their associated `part` numbers.\n * @returns {qq.Promise}\n */\n send: function(id, uploadId, etagEntries) {\n var promise = new qq.Promise(),\n body = getCompleteRequestBody(etagEntries);\n\n getHeaders(id, uploadId, body).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 complete multipart upload request for \" + id);\n\n pendingCompleteRequests[id] = promise;\n delete headers[\"Content-Type\"];\n\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .withPayload(body)\n .send();\n }, promise.failure);\n\n return promise;\n }\n });\n};\n","/*globals qq */\n/**\n * Ajax requester used to send an [\"Abort Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadAbort.html)\n * request to S3 via the REST API.\n\n * @param o\n * @constructor\n */\nqq.s3.AbortMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n endpointStore: null,\n signatureSpec: null,\n maxConnections: 3,\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n // Transport for requesting signatures (for the \"Complete\" requests) from the local server\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Attach all required headers (including Authorization) to the \"Abort\" request. This is a promissory function\n * that will fulfill the associated promise once all headers have been attached or when an error has occurred that\n * prevents headers from being attached.\n *\n * @param id Associated file ID\n * @param uploadId ID of the associated upload, according to AWS\n * @returns {qq.Promise}\n */\n function getHeaders(id, uploadId) {\n var headers = {},\n promise = new qq.Promise(),\n bucket = options.getBucket(id),\n host = options.getHost(id),\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, options.getKey(id))\n .withUploadId(uploadId);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Abort MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleAbortRequestComplete(id, xhr, isError) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n errorEls = responseDoc.getElementsByTagName(\"Error\"),\n awsErrorMsg;\n\n options.log(qq.format(\"Abort response status {}, body = {}\", xhr.status, xhr.responseText));\n\n // If the base requester has determine this a failure, give up.\n if (isError) {\n options.log(qq.format(\"Abort Multipart Upload request for {} failed with status {}.\", id, xhr.status), \"error\");\n }\n else {\n // Make sure the correct bucket and key has been specified in the XML response from AWS.\n if (errorEls.length) {\n isError = true;\n awsErrorMsg = responseDoc.getElementsByTagName(\"Message\")[0].textContent;\n options.log(qq.format(\"Failed to Abort Multipart Upload request for {}. Error: {}\", id, awsErrorMsg), \"error\");\n }\n else {\n options.log(qq.format(\"Abort MPU request succeeded for file ID {}.\", id));\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [\"DELETE\"],\n method: options.method,\n contentType: null,\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleAbortRequestComplete,\n successfulResponseCodes: {\n DELETE: [204]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Abort\" request.\n *\n * @param id ID associated with the file.\n * @param uploadId AWS uploadId for this file\n */\n send: function(id, uploadId) {\n getHeaders(id, uploadId).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 Abort multipart upload request for \" + id);\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .send();\n });\n }\n });\n};\n","/*globals qq */\n/**\n * Upload handler used by the upload to S3 module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to S3 buckets via the associated AWS API.\n *\n * If chunking is supported and enabled, the S3 Multipart Upload REST API is utilized.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.s3.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var getName = proxy.getName,\n log = proxy.log,\n clockDrift = spec.clockDrift,\n expectedStatus = 200,\n onGetBucket = spec.getBucket,\n onGetHost = spec.getHost,\n onGetKeyName = spec.getKeyName,\n filenameParam = spec.filenameParam,\n paramsStore = spec.paramsStore,\n endpointStore = spec.endpointStore,\n aclStore = spec.aclStore,\n reducedRedundancy = spec.objectProperties.reducedRedundancy,\n region = spec.objectProperties.region,\n serverSideEncryption = spec.objectProperties.serverSideEncryption,\n validation = spec.validation,\n signature = qq.extend({region: region, drift: clockDrift}, spec.signature),\n handler = this,\n credentialsProvider = spec.signature.credentialsProvider,\n\n chunked = {\n // Sends a \"Complete Multipart Upload\" request and then signals completion of the upload\n // when the response to this request has been parsed.\n combine: function(id) {\n var uploadId = handler._getPersistableData(id).uploadId,\n etagMap = handler._getPersistableData(id).etags,\n result = new qq.Promise();\n\n requesters.completeMultipart.send(id, uploadId, etagMap).then(\n result.success,\n\n function failure(reason, xhr) {\n result.failure(upload.done(id, xhr).response, xhr);\n }\n );\n\n return result;\n },\n\n // The last step in handling a chunked upload. This is called after each chunk has been sent.\n // The request may be successful, or not. If it was successful, we must extract the \"ETag\" element\n // in the XML response and store that along with the associated part number.\n // We need these items to \"Complete\" the multipart upload after all chunks have been successfully sent.\n done: function(id, xhr, chunkIdx) {\n var response = upload.response.parse(id, xhr),\n etag;\n\n if (response.success) {\n etag = xhr.getResponseHeader(\"ETag\");\n\n if (!handler._getPersistableData(id).etags) {\n handler._getPersistableData(id).etags = [];\n }\n handler._getPersistableData(id).etags.push({part: chunkIdx + 1, etag: etag});\n }\n },\n\n /**\n * Determines headers that must be attached to the chunked (Multipart Upload) request. One of these headers is an\n * Authorization value, which must be determined by asking the local server to sign the request first. So, this\n * function returns a promise. Once all headers are determined, the `success` method of the promise is called with\n * the headers object. If there was some problem determining the headers, we delegate to the caller's `failure`\n * callback.\n *\n * @param id File ID\n * @param chunkIdx Index of the chunk to PUT\n * @returns {qq.Promise}\n */\n initHeaders: function(id, chunkIdx, blob) {\n var headers = {},\n bucket = upload.bucket.getName(id),\n host = upload.host.getName(id),\n key = upload.key.urlSafe(id),\n promise = new qq.Promise(),\n signatureConstructor = requesters.restSignature.constructStringToSign\n (requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key)\n .withPartNum(chunkIdx + 1)\n .withContent(blob)\n .withUploadId(handler._getPersistableData(id).uploadId);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n requesters.restSignature.getSignature(id + \".\" + chunkIdx, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n },\n\n put: function(id, chunkIdx) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx),\n domain = spec.endpointStore.get(id),\n promise = new qq.Promise();\n\n // Add appropriate headers to the multipart upload request.\n // Once these have been determined (asynchronously) attach the headers and send the chunk.\n chunked.initHeaders(id, chunkIdx, chunkData.blob).then(function(headers, endOfUrl) {\n if (xhr._cancelled) {\n log(qq.format(\"Upload of item {}.{} cancelled. Upload will not start after successful signature request.\", id, chunkIdx));\n promise.failure({error: \"Chunk upload cancelled\"});\n }\n else {\n var url = domain + \"/\" + endOfUrl;\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n upload.track(id, xhr, chunkIdx).then(promise.success, promise.failure);\n xhr.open(\"PUT\", url, true);\n\n qq.each(headers, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n\n xhr.send(chunkData.blob);\n }\n }, function() {\n promise.failure({error: \"Problem signing the chunk!\"}, xhr);\n });\n\n return promise;\n },\n\n send: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n chunked.setup(id).then(\n // The \"Initiate\" request succeeded. We are ready to send the first chunk.\n function() {\n chunked.put(id, chunkIdx).then(promise.success, promise.failure);\n },\n\n // We were unable to initiate the chunked upload process.\n function(errorMessage, xhr) {\n promise.failure({error: errorMessage}, xhr);\n }\n );\n\n return promise;\n },\n\n /**\n * Sends an \"Initiate Multipart Upload\" request to S3 via the REST API, but only if the MPU has not already been\n * initiated.\n *\n * @param id Associated file ID\n * @returns {qq.Promise} A promise that is fulfilled when the initiate request has been sent and the response has been parsed.\n */\n setup: function(id) {\n var promise = new qq.Promise(),\n uploadId = handler._getPersistableData(id).uploadId,\n uploadIdPromise = new qq.Promise();\n\n if (!uploadId) {\n handler._getPersistableData(id).uploadId = uploadIdPromise;\n requesters.initiateMultipart.send(id).then(\n function(uploadId) {\n handler._getPersistableData(id).uploadId = uploadId;\n uploadIdPromise.success(uploadId);\n promise.success(uploadId);\n },\n function(errorMsg, xhr) {\n handler._getPersistableData(id).uploadId = null;\n promise.failure(errorMsg, xhr);\n uploadIdPromise.failure(errorMsg, xhr);\n }\n );\n }\n else if (uploadId instanceof qq.Promise) {\n uploadId.then(function(uploadId) {\n promise.success(uploadId);\n });\n }\n else {\n promise.success(uploadId);\n }\n\n return promise;\n }\n },\n\n requesters = {\n abortMultipart: new qq.s3.AbortMultipartAjaxRequester({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log,\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n }\n }),\n\n completeMultipart: new qq.s3.CompleteMultipartAjaxRequester({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log,\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n }\n }),\n\n initiateMultipart: new qq.s3.InitiateMultipartAjaxRequester({\n filenameParam: filenameParam,\n endpointStore: endpointStore,\n paramsStore: paramsStore,\n signatureSpec: signature,\n aclStore: aclStore,\n reducedRedundancy: reducedRedundancy,\n serverSideEncryption: serverSideEncryption,\n cors: spec.cors,\n log: log,\n getContentType: function(id) {\n return handler._getMimeType(id);\n },\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n },\n getName: function(id) {\n return getName(id);\n }\n }),\n\n policySignature: new qq.s3.RequestSigner({\n expectingPolicy: true,\n signatureSpec: signature,\n cors: spec.cors,\n log: log\n }),\n\n restSignature: new qq.s3.RequestSigner({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log\n })\n },\n\n simple = {\n /**\n * Used for simple (non-chunked) uploads to determine the parameters to send along with the request. Part of this\n * process involves asking the local server to sign the request, so this function returns a promise. The promise\n * is fulfilled when all parameters are determined, or when we determine that all parameters cannot be calculated\n * due to some error.\n *\n * @param id File ID\n * @returns {qq.Promise}\n */\n initParams: function(id) {\n /*jshint -W040 */\n var customParams = paramsStore.get(id);\n customParams[filenameParam] = getName(id);\n\n return qq.s3.util.generateAwsParams({\n endpoint: endpointStore.get(id),\n clockDrift: clockDrift,\n params: customParams,\n type: handler._getMimeType(id),\n bucket: upload.bucket.getName(id),\n key: handler.getThirdPartyFileId(id),\n accessKey: credentialsProvider.get().accessKey,\n sessionToken: credentialsProvider.get().sessionToken,\n acl: aclStore.get(id),\n expectedStatus: expectedStatus,\n minFileSize: validation.minSizeLimit,\n maxFileSize: validation.maxSizeLimit,\n reducedRedundancy: reducedRedundancy,\n region: region,\n serverSideEncryption: serverSideEncryption,\n signatureVersion: signature.version,\n log: log\n },\n qq.bind(requesters.policySignature.getSignature, this, id));\n },\n\n send: function(id) {\n var promise = new qq.Promise(),\n xhr = handler._createXhr(id),\n fileOrBlob = handler.getFile(id);\n\n handler._registerProgressHandler(id);\n upload.track(id, xhr).then(promise.success, promise.failure);\n\n // Delegate to a function the sets up the XHR request and notifies us when it is ready to be sent, along w/ the payload.\n simple.setup(id, xhr, fileOrBlob).then(function(toSend) {\n log(\"Sending upload request for \" + id);\n xhr.send(toSend);\n }, promise.failure);\n\n return promise;\n },\n\n /**\n * Starts the upload process by delegating to an async function that determine parameters to be attached to the\n * request. If all params can be determined, we are called back with the params and the caller of this function is\n * informed by invoking the `success` method on the promise returned by this function, passing the payload of the\n * request. If some error occurs here, we delegate to a function that signals a failure for this upload attempt.\n *\n * Note that this is only used by the simple (non-chunked) upload process.\n *\n * @param id File ID\n * @param xhr XMLHttpRequest to use for the upload\n * @param fileOrBlob `File` or `Blob` to send\n * @returns {qq.Promise}\n */\n setup: function(id, xhr, fileOrBlob) {\n var formData = new FormData(),\n endpoint = endpointStore.get(id),\n url = endpoint,\n promise = new qq.Promise();\n\n simple.initParams(id).then(\n // Success - all params determined\n function(awsParams) {\n xhr.open(\"POST\", url, true);\n\n qq.obj2FormData(awsParams, formData);\n\n // AWS requires the file field be named \"file\".\n formData.append(\"file\", fileOrBlob);\n\n promise.success(formData);\n },\n\n // Failure - we couldn't determine some params (likely the signature)\n function(errorMessage) {\n promise.failure({error: errorMessage});\n }\n );\n\n return promise;\n }\n },\n\n upload = {\n /**\n * Note that this is called when an upload has reached a termination point,\n * regardless of success/failure. For example, it is called when we have\n * encountered an error during the upload or when the file may have uploaded successfully.\n *\n * @param id file ID\n */\n bucket: {\n promise: function(id) {\n var promise = new qq.Promise(),\n cachedBucket = handler._getFileState(id).bucket;\n\n if (cachedBucket) {\n promise.success(cachedBucket);\n }\n else {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n promise.success(bucket);\n }, promise.failure);\n }\n\n return promise;\n },\n\n getName: function(id) {\n return handler._getFileState(id).bucket;\n }\n },\n\n host: {\n promise: function(id) {\n var promise = new qq.Promise(),\n cachedHost = handler._getFileState(id).host;\n\n if (cachedHost) {\n promise.success(cachedHost);\n }\n else {\n onGetHost(id).then(function(host) {\n handler._getFileState(id).host = host;\n promise.success(host);\n }, promise.failure);\n }\n\n return promise;\n },\n\n getName: function(id) {\n return handler._getFileState(id).host;\n }\n },\n\n done: function(id, xhr) {\n var response = upload.response.parse(id, xhr),\n isError = response.success !== true;\n\n if (isError && upload.response.shouldReset(response.code)) {\n log(\"This is an unrecoverable error, we must restart the upload entirely on the next retry attempt.\", \"error\");\n response.reset = true;\n }\n\n return {\n success: !isError,\n response: response\n };\n },\n\n key: {\n promise: function(id) {\n var promise = new qq.Promise(),\n key = handler.getThirdPartyFileId(id);\n\n /* jshint eqnull:true */\n if (key == null) {\n handler._setThirdPartyFileId(id, promise);\n onGetKeyName(id, getName(id)).then(\n function(keyName) {\n handler._setThirdPartyFileId(id, keyName);\n promise.success(keyName);\n },\n function(errorReason) {\n handler._setThirdPartyFileId(id, null);\n promise.failure(errorReason);\n }\n );\n }\n else if (qq.isGenericPromise(key)) {\n key.then(promise.success, promise.failure);\n }\n else {\n promise.success(key);\n }\n\n return promise;\n },\n\n urlSafe: function(id) {\n var encodedKey = handler.getThirdPartyFileId(id);\n return qq.s3.util.uriEscapePath(encodedKey);\n }\n },\n\n response: {\n parse: function(id, xhr) {\n var response = {},\n parsedErrorProps;\n\n try {\n log(qq.format(\"Received response status {} with body: {}\", xhr.status, xhr.responseText));\n\n if (xhr.status === expectedStatus) {\n response.success = true;\n }\n else {\n parsedErrorProps = upload.response.parseError(xhr.responseText);\n\n if (parsedErrorProps) {\n response.error = parsedErrorProps.message;\n response.code = parsedErrorProps.code;\n }\n }\n }\n catch (error) {\n log(\"Error when attempting to parse xhr response text (\" + error.message + \")\", \"error\");\n }\n\n return response;\n },\n\n /**\n * This parses an XML response by extracting the \"Message\" and \"Code\" elements that accompany AWS error responses.\n *\n * @param awsResponseXml XML response from AWS\n * @returns {object} Object w/ `code` and `message` properties, or undefined if we couldn't find error info in the XML document.\n */\n parseError: function(awsResponseXml) {\n var parser = new DOMParser(),\n parsedDoc = parser.parseFromString(awsResponseXml, \"application/xml\"),\n errorEls = parsedDoc.getElementsByTagName(\"Error\"),\n errorDetails = {},\n codeEls, messageEls;\n\n if (errorEls.length) {\n codeEls = parsedDoc.getElementsByTagName(\"Code\");\n messageEls = parsedDoc.getElementsByTagName(\"Message\");\n\n if (messageEls.length) {\n errorDetails.message = messageEls[0].textContent;\n }\n\n if (codeEls.length) {\n errorDetails.code = codeEls[0].textContent;\n }\n\n return errorDetails;\n }\n },\n\n // Determine if the upload should be restarted on the next retry attempt\n // based on the error code returned in the response from AWS.\n shouldReset: function(errorCode) {\n /*jshint -W014 */\n return errorCode === \"EntityTooSmall\"\n || errorCode === \"InvalidPart\"\n || errorCode === \"InvalidPartOrder\"\n || errorCode === \"NoSuchUpload\";\n }\n },\n\n start: function(id, optChunkIdx) {\n var promise = new qq.Promise();\n\n upload.key.promise(id).then(function() {\n upload.bucket.promise(id).then(function() {\n upload.host.promise(id).then(function() {\n /* jshint eqnull:true */\n if (optChunkIdx == null) {\n simple.send(id).then(promise.success, promise.failure);\n }\n else {\n chunked.send(id, optChunkIdx).then(promise.success, promise.failure);\n }\n });\n });\n },\n function(errorReason) {\n promise.failure({error: errorReason});\n });\n\n return promise;\n },\n\n track: function(id, xhr, optChunkIdx) {\n var promise = new qq.Promise();\n\n xhr.onreadystatechange = function() {\n if (xhr.readyState === 4) {\n var result;\n\n /* jshint eqnull:true */\n if (optChunkIdx == null) {\n result = upload.done(id, xhr);\n promise[result.success ? \"success\" : \"failure\"](result.response, xhr);\n }\n else {\n chunked.done(id, xhr, optChunkIdx);\n result = upload.done(id, xhr);\n promise[result.success ? \"success\" : \"failure\"](result.response, xhr);\n }\n }\n };\n\n return promise;\n }\n };\n\n qq.extend(this, {\n uploadChunk: upload.start,\n uploadFile: upload.start\n });\n\n qq.extend(this, new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"s3\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var uploadId = handler._getPersistableData(id) && handler._getPersistableData(id).uploadId,\n existedInLocalStorage = handler._maybeDeletePersistedChunkData(id);\n\n if (uploadId !== undefined && existedInLocalStorage) {\n requesters.abortMultipart.send(id, uploadId);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return chunked.combine(id);\n },\n\n _getLocalStorageId: function(id) {\n var baseStorageId = super_._getLocalStorageId(id),\n bucketName = upload.bucket.getName(id);\n\n return baseStorageId + \"-\" + bucketName;\n }\n };\n });\n};\n","/*globals qq */\n/**\n * Upload handler used by the upload to S3 module that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to S3 buckets via the associated\n * AWS API.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.s3.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n clockDrift = options.clockDrift,\n onUuidChanged = proxy.onUuidChanged,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n onGetBucket = options.getBucket,\n onGetKeyName = options.getKeyName,\n filenameParam = options.filenameParam,\n paramsStore = options.paramsStore,\n endpointStore = options.endpointStore,\n aclStore = options.aclStore,\n reducedRedundancy = options.objectProperties.reducedRedundancy,\n region = options.objectProperties.region,\n serverSideEncryption = options.objectProperties.serverSideEncryption,\n validation = options.validation,\n signature = options.signature,\n successRedirectUrl = options.iframeSupport.localBlankPagePath,\n credentialsProvider = options.signature.credentialsProvider,\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n signatureSpec: signature,\n cors: options.cors,\n log: log\n });\n\n if (successRedirectUrl === undefined) {\n throw new Error(\"successRedirectEndpoint MUST be defined if you intend to use browsers that do not support the File API!\");\n }\n\n /**\n * Attempt to parse the contents of an iframe after receiving a response from the server. If the contents cannot be\n * read (perhaps due to a security error) it is safe to assume that the upload was not successful since Amazon should\n * have redirected to a known endpoint that should provide a parseable response.\n *\n * @param id ID of the associated file\n * @param iframe target of the form submit\n * @returns {boolean} true if the contents can be read, false otherwise\n */\n function isValidResponse(id, iframe) {\n var response,\n endpoint = options.endpointStore.get(id),\n bucket = handler._getFileState(id).bucket,\n doc,\n innerHtml,\n responseData;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n responseData = qq.s3.util.parseIframeResponse(iframe);\n if (responseData.bucket === bucket &&\n responseData.key === qq.s3.util.encodeQueryStringParam(handler.getThirdPartyFileId(id))) {\n\n return true;\n }\n\n log(\"Response from AWS included an unexpected bucket or key name.\", \"error\");\n\n }\n catch (error) {\n log(\"Error when attempting to parse form upload response (\" + error.message + \")\", \"error\");\n }\n\n return false;\n }\n\n function generateAwsParams(id) {\n /*jshint -W040 */\n var customParams = paramsStore.get(id);\n\n customParams[filenameParam] = getName(id);\n\n return qq.s3.util.generateAwsParams({\n endpoint: endpointStore.get(id),\n clockDrift: clockDrift,\n params: customParams,\n bucket: handler._getFileState(id).bucket,\n key: handler.getThirdPartyFileId(id),\n accessKey: credentialsProvider.get().accessKey,\n sessionToken: credentialsProvider.get().sessionToken,\n acl: aclStore.get(id),\n minFileSize: validation.minSizeLimit,\n maxFileSize: validation.maxSizeLimit,\n successRedirectUrl: successRedirectUrl,\n reducedRedundancy: reducedRedundancy,\n region: region,\n serverSideEncryption: serverSideEncryption,\n signatureVersion: signature.version,\n log: log\n },\n qq.bind(getSignatureAjaxRequester.getSignature, this, id));\n }\n\n /**\n * Creates form, that will be submitted to iframe\n */\n function createForm(id, iframe) {\n var promise = new qq.Promise(),\n method = \"POST\",\n endpoint = options.endpointStore.get(id),\n fileName = getName(id);\n\n generateAwsParams(id).then(function(params) {\n var form = handler._initFormForUpload({\n method: method,\n endpoint: endpoint,\n params: params,\n paramsInBody: true,\n targetName: iframe.name\n });\n\n promise.success(form);\n }, function(errorMessage) {\n promise.failure(errorMessage);\n handleFinishedUpload(id, iframe, fileName, {error: errorMessage});\n });\n\n return promise;\n }\n\n function handleUpload(id) {\n var iframe = handler._createIframe(id),\n input = handler.getInput(id),\n promise = new qq.Promise();\n\n createForm(id, iframe).then(function(form) {\n form.appendChild(input);\n\n // Register a callback when the response comes in from S3\n handler._attachLoadEvent(iframe, function(response) {\n log(\"iframe loaded\");\n\n // If the common response handler has determined success or failure immediately\n if (response) {\n // If there is something fundamentally wrong with the response (such as iframe content is not accessible)\n if (response.success === false) {\n log(\"Amazon likely rejected the upload request\", \"error\");\n promise.failure(response);\n }\n }\n // The generic response (iframe onload) handler was not able to make a determination regarding the success of the request\n else {\n response = {};\n response.success = isValidResponse(id, iframe);\n\n // If the more specific response handle detected a problem with the response from S3\n if (response.success === false) {\n log(\"A success response was received by Amazon, but it was invalid in some way.\", \"error\");\n promise.failure(response);\n }\n else {\n qq.extend(response, qq.s3.util.parseIframeResponse(iframe));\n promise.success(response);\n }\n }\n\n handleFinishedUpload(id, iframe);\n });\n\n log(\"Sending upload request for \" + id);\n form.submit();\n qq(form).remove();\n }, promise.failure);\n\n return promise;\n }\n\n function handleFinishedUpload(id, iframe) {\n handler._detachLoadEvent(id);\n iframe && qq(iframe).remove();\n }\n\n qq.extend(this, new qq.FormUploadHandler({\n options: {\n isCors: false,\n inputName: \"file\"\n },\n\n proxy: {\n onCancel: options.onCancel,\n onUuidChanged: onUuidChanged,\n getName: getName,\n getUuid: getUuid,\n log: log\n }\n }));\n\n qq.extend(this, {\n uploadFile: function(id) {\n var name = getName(id),\n promise = new qq.Promise();\n\n if (handler.getThirdPartyFileId(id)) {\n if (handler._getFileState(id).bucket) {\n handleUpload(id).then(promise.success, promise.failure);\n }\n else {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n handleUpload(id).then(promise.success, promise.failure);\n });\n }\n }\n else {\n // The S3 uploader module will either calculate the key or ask the server for it\n // and will call us back once it is known.\n onGetKeyName(id, name).then(function(key) {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n handler._setThirdPartyFileId(id, key);\n handleUpload(id).then(promise.success, promise.failure);\n }, function(errorReason) {\n promise.failure({error: errorReason});\n });\n }, function(errorReason) {\n promise.failure({error: errorReason});\n });\n }\n\n return promise;\n }\n });\n};\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.core.min.js b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.core.min.js
new file mode 100644
index 000000000000..649adee9072c
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.core.min.js
@@ -0,0 +1,8 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+!function(global,global){var qq=function(e){"use strict";return{hide:function(){return e.style.display="none",this},attach:function(t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n),function(){qq(e).detach(t,n)}},detach:function(t,n){return e.removeEventListener?e.removeEventListener(t,n,!1):e.attachEvent&&e.detachEvent("on"+t,n),this},contains:function(t){return!!t&&(e===t||(e.contains?e.contains(t):!!(8&t.compareDocumentPosition(e))))},insertBefore:function(t){return t.parentNode.insertBefore(e,t),this},remove:function(){return e.parentNode.removeChild(e),this},css:function(t){if(null==e.style)throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");return null!=t.opacity&&"string"!=typeof e.style.opacity&&"undefined"!=typeof e.filters&&(t.filter="alpha(opacity="+Math.round(100*t.opacity)+")"),qq.extend(e.style,t),this},hasClass:function(t,n){var i=new RegExp("(^| )"+t+"( |$)");return i.test(e.className)||!(!n||!i.test(e.parentNode.className))},addClass:function(t){return qq(e).hasClass(t)||(e.className+=" "+t),this},removeClass:function(t){var n=new RegExp("(^| )"+t+"( |$)");return e.className=e.className.replace(n," ").replace(/^\s+|\s+$/g,""),this},getByClass:function(t,n){var i,r=[];return n&&e.querySelector?e.querySelector("."+t):e.querySelectorAll?e.querySelectorAll("."+t):(i=e.getElementsByTagName("*"),qq.each(i,function(e,n){qq(n).hasClass(t)&&r.push(n)}),n?r[0]:r)},getFirstByClass:function(t){return qq(e).getByClass(t,!0)},children:function(){for(var t=[],n=e.firstChild;n;)1===n.nodeType&&t.push(n),n=n.nextSibling;return t},setText:function(t){return e.innerText=t,e.textContent=t,this},clearText:function(){return qq(e).setText("")},hasAttribute:function(t){var n;return e.hasAttribute?!!e.hasAttribute(t)&&null==/^false$/i.exec(e.getAttribute(t)):(n=e[t],void 0!==n&&null==/^false$/i.exec(n))}}};!function(){"use strict";qq.canvasToBlob=function(e,t,n){return qq.dataUriToBlob(e.toDataURL(t,n))},qq.dataUriToBlob=function(e){var t,n,i,r,o=function(e,t){var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})};return n=e.split(",")[0].indexOf("base64")>=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),r=e.split(",")[0].split(":")[1].split(";")[0],t=new ArrayBuffer(n.length),i=new Uint8Array(t),qq.each(n,function(e,t){i[e]=t.charCodeAt(0)}),o(t,r)},qq.log=function(e,t){window.console&&(t&&"info"!==t?window.console[t]?window.console[t](e):window.console.log("<"+t+"> "+e):window.console.log(e))},qq.isObject=function(e){return e&&!e.nodeType&&"[object Object]"===Object.prototype.toString.call(e)},qq.isFunction=function(e){return"function"==typeof e},qq.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)||e&&window.ArrayBuffer&&e.buffer&&e.buffer.constructor===ArrayBuffer},qq.isItemList=function(e){return"[object DataTransferItemList]"===Object.prototype.toString.call(e)},qq.isNodeList=function(e){return"[object NodeList]"===Object.prototype.toString.call(e)||e.item&&e.namedItem},qq.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},qq.trimStr=function(e){return String.prototype.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},qq.format=function(e){var t=Array.prototype.slice.call(arguments,1),n=e,i=n.indexOf("{}");return qq.each(t,function(e,t){var r=n.substring(0,i),o=n.substring(i+2);if(n=r+t+o,i=n.indexOf("{}",i+t.length),i<0)return!1}),n},qq.isFile=function(e){return window.File&&"[object File]"===Object.prototype.toString.call(e)},qq.isFileList=function(e){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(e)},qq.isFileOrInput=function(e){return qq.isFile(e)||qq.isInput(e)},qq.isInput=function(e,t){var n=function(e){var n=e.toLowerCase();return t?"file"!==n:"file"===n};return!!(window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(e)&&e.type&&n(e.type))||!!(e.tagName&&"input"===e.tagName.toLowerCase()&&e.type&&n(e.type))},qq.isBlob=function(e){if(window.Blob&&"[object Blob]"===Object.prototype.toString.call(e))return!0},qq.isXhrUploadSupported=function(){var e=document.createElement("input");return e.type="file",void 0!==e.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&"undefined"!=typeof qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(e){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(e){return e.items&&e.items.length>0&&e.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(e,t,n){var i=e.slice||e.mozSlice||e.webkitSlice;return i.call(e,t,n)},qq.arrayBufferToHex=function(e){var t="",n=new Uint8Array(e);return qq.each(n,function(e,n){var i=n.toString(16);i.length<2&&(i="0"+i),t+=i}),t},qq.readBlobToHex=function(e,t,n){var i=qq.sliceBlob(e,t,t+n),r=new FileReader,o=new qq.Promise;return r.onload=function(){o.success(qq.arrayBufferToHex(r.result))},r.onerror=o.failure,r.readAsArrayBuffer(i),o},qq.extend=function(e,t,n){return qq.each(t,function(t,i){n&&qq.isObject(i)?(void 0===e[t]&&(e[t]={}),qq.extend(e[t],i,!0)):e[t]=i}),e},qq.override=function(e,t){var n={},i=t(n);return qq.each(i,function(t,i){void 0!==e[t]&&(n[t]=e[t]),e[t]=i}),e},qq.indexOf=function(e,t,n){if(e.indexOf)return e.indexOf(t,n);n=n||0;var i=e.length;for(n<0&&(n+=i);n=0},qq.safari=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Apple")!==-1},qq.chrome=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Google")!==-1},qq.opera=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Opera")!==-1},qq.firefox=function(){return!qq.edge()&&!qq.ie11()&&navigator.userAgent.indexOf("Mozilla")!==-1&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return navigator.userAgent.toLowerCase().indexOf("android")!==-1},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 6_")!==-1},qq.ios7=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 7_")!==-1},qq.ios8=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_")!==-1},qq.ios800=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_0 ")!==-1},qq.ios=function(){return navigator.userAgent.indexOf("iPad")!==-1||navigator.userAgent.indexOf("iPod")!==-1||navigator.userAgent.indexOf("iPhone")!==-1},qq.iosChrome=function(){return qq.ios()&&navigator.userAgent.indexOf("CriOS")!==-1},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&navigator.userAgent.indexOf("Safari")!==-1},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},qq.toElement=function(){var e=document.createElement("div");return function(t){e.innerHTML=t;var n=e.firstChild;return e.removeChild(n),n}}(),qq.each=function(e,t){var n,i;if(e)if(window.Storage&&e.constructor===window.Storage)for(n=0;n0)return e.substr(t,e.length-t)},qq.getFilename=function(e){return qq.isInput(e)?e.value.replace(/.*(\/|\\)/,""):qq.isFile(e)&&null!==e.fileName&&void 0!==e.fileName?e.fileName:e.name},qq.DisposeSupport=function(){var e=[];return{dispose:function(){var t;do t=e.shift(),t&&t();while(t)},attach:function(){var e=arguments;this.addDisposer(qq(e[0]).attach.apply(this,Array.prototype.slice.call(arguments,1)))},addDisposer:function(t){e.push(t)}}}}(),function(){"use strict";"function"==typeof define&&define.amd?define(function(){return qq}):"undefined"!=typeof module&&module.exports?module.exports=qq:global.qq=qq}(),function(){"use strict";qq.Error=function(e){this.message="[Fine Uploader "+qq.version+"] "+e},qq.Error.prototype=new Error}(),qq.version="5.13.0",qq.supportedFeatures=function(){"use strict";function e(){var e,t=!0;try{e=document.createElement("input"),e.type="file",qq(e).hide(),e.disabled&&(t=!1)}catch(e){t=!1}return t}function t(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/)}function n(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/)}function i(){if(window.XMLHttpRequest){var e=qq.createXhrInstance();return void 0!==e.withCredentials}return!1}function r(){return void 0!==window.XDomainRequest}function o(){return!!i()||r()}function a(){return void 0!==document.createElement("input").webkitdirectory}function s(){try{return!!window.localStorage&&qq.isFunction(window.localStorage.setItem)}catch(e){return!1}}function u(){var e=document.createElement("span");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&!qq.android()&&!qq.ios()}var c,l,d,p,q,f,h,g,m,_,S,b,v,y,w;return c=e(),p=c&&qq.isXhrUploadSupported(),l=p&&!qq.androidStock(),d=p&&u(),q=d&&t(),f=p&&qq.isFileChunkingSupported(),h=p&&f&&s(),g=p&&n(),m=c&&(void 0!==window.postMessage||p),S=i(),_=r(),b=o(),v=a(),y=p&&void 0!==window.FileReader,w=function(){return!!p&&(!qq.androidStock()&&!qq.iosChrome())}(),{ajaxUploading:p,blobUploading:l,canDetermineSize:p,chunking:f,deleteFileCors:b,deleteFileCorsXdr:_,deleteFileCorsXhr:S,dialogElement:!!window.HTMLDialogElement,fileDrop:d,folderDrop:q,folderSelection:v,imagePreviews:y,imageValidation:y,itemSizeValidation:p,pause:f,progressBar:w,resume:h,scaling:y&&l,tiffPreviews:qq.safari(),unlimitedScaledImageSize:!qq.ios(),uploading:c,uploadCors:m,uploadCustomHeaders:p,uploadNonMultipart:p,uploadViaPaste:g}}(),qq.isGenericPromise=function(e){"use strict";return!!(e&&e.then&&qq.isFunction(e.then))},qq.Promise=function(){"use strict";var e,t,n=[],i=[],r=[],o=0;qq.extend(this,{then:function(r,a){return 0===o?(r&&n.push(r),a&&i.push(a)):o===-1?a&&a.apply(null,t):r&&r.apply(null,e),this},done:function(n){return 0===o?r.push(n):n.apply(null,void 0===t?e:t),this},success:function(){return o=1,e=arguments,n.length&&qq.each(n,function(t,n){n.apply(null,e)}),r.length&&qq.each(r,function(t,n){n.apply(null,e)}),this},failure:function(){return o=-1,t=arguments,i.length&&qq.each(i,function(e,n){n.apply(null,t)}),r.length&&qq.each(r,function(e,n){n.apply(null,t)}),this}})},qq.BlobProxy=function(e,t){"use strict";qq.extend(this,{referenceBlob:e,create:function(){return t(e)}})},qq.UploadButton=function(e){"use strict";function t(){var e=document.createElement("input");return e.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME,i),e.setAttribute("title",a.title),r.setMultiple(a.multiple,e),a.folders&&qq.supportedFeatures.folderSelection&&e.setAttribute("webkitdirectory",""),a.acceptFiles&&e.setAttribute("accept",a.acceptFiles),e.setAttribute("type","file"),e.setAttribute("name",a.name),qq(e).css({position:"absolute",right:0,top:0,fontFamily:"Arial",fontSize:qq.ie()&&!qq.ie8()?"3500px":"118px",margin:0,padding:0,cursor:"pointer",opacity:0}),!qq.ie7()&&qq(e).css({height:"100%"}),a.element.appendChild(e),o.attach(e,"change",function(){a.onChange(e)}),o.attach(e,"mouseover",function(){qq(a.element).addClass(a.hoverClass)}),o.attach(e,"mouseout",function(){qq(a.element).removeClass(a.hoverClass)}),o.attach(e,"focus",function(){qq(a.element).addClass(a.focusClass)}),o.attach(e,"blur",function(){qq(a.element).removeClass(a.focusClass)}),e}var n,i,r=this,o=new qq.DisposeSupport,a={acceptFiles:null,element:null,focusClass:"qq-upload-button-focus",folders:!1,hoverClass:"qq-upload-button-hover",ios8BrowserCrashWorkaround:!1,multiple:!1,name:"qqfile",onChange:function(e){},title:null};qq.extend(a,e),i=qq.getUniqueId(),qq(a.element).css({position:"relative",overflow:"hidden",direction:"ltr"}),qq.extend(this,{getInput:function(){return n},getButtonId:function(){return i},setMultiple:function(e,t){var n=t||this.getInput();a.ios8BrowserCrashWorkaround&&qq.ios8()&&(qq.iosChrome()||qq.iosSafariWebView())?n.setAttribute("multiple",""):e?n.setAttribute("multiple",""):n.removeAttribute("multiple")},setAcceptFiles:function(e){e!==a.acceptFiles&&n.setAttribute("accept",e)},reset:function(){n.parentNode&&qq(n).remove(),qq(a.element).removeClass(a.focusClass),n=null,n=t()}}),n=t()},qq.UploadButton.BUTTON_ID_ATTR_NAME="qq-button-id",qq.UploadData=function(e){"use strict";function t(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(r[n])}),t}return r[e]}function n(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(r[o[n]])}),t}return r[o[e]]}function i(e){var t=[],n=[].concat(e);return qq.each(n,function(e,n){var i=a[n];void 0!==i&&qq.each(i,function(e,n){t.push(r[n])})}),t}var r=[],o={},a={},s={},u={};qq.extend(this,{addFile:function(t){var n=t.status||qq.status.SUBMITTING,i=r.push({name:t.name,originalName:t.name,uuid:t.uuid,size:null==t.size?-1:t.size,status:n})-1;return t.batchId&&(r[i].batchId=t.batchId,void 0===u[t.batchId]&&(u[t.batchId]=[]),u[t.batchId].push(i)),t.proxyGroupId&&(r[i].proxyGroupId=t.proxyGroupId,void 0===s[t.proxyGroupId]&&(s[t.proxyGroupId]=[]),s[t.proxyGroupId].push(i)),r[i].id=i,o[t.uuid]=i,void 0===a[n]&&(a[n]=[]),a[n].push(i),e.onStatusChange(i,null,n),i},retrieve:function(e){return qq.isObject(e)&&r.length?void 0!==e.id?t(e.id):void 0!==e.uuid?n(e.uuid):e.status?i(e.status):void 0:qq.extend([],r,!0)},reset:function(){r=[],o={},a={},u={}},setStatus:function(t,n){var i=r[t].status,o=qq.indexOf(a[i],t);a[i].splice(o,1),r[t].status=n,void 0===a[n]&&(a[n]=[]),a[n].push(t),e.onStatusChange(t,i,n)},uuidChanged:function(e,t){var n=r[e].uuid;r[e].uuid=t,o[t]=e,delete o[n]},updateName:function(e,t){r[e].name=t},updateSize:function(e,t){r[e].size=t},setParentId:function(e,t){r[e].parentId=t},getIdsInProxyGroup:function(e){var t=r[e].proxyGroupId;return t?s[t]:[]},getIdsInBatch:function(e){var t=r[e].batchId;return u[t]}})},qq.status={SUBMITTING:"submitting",SUBMITTED:"submitted",REJECTED:"rejected",QUEUED:"queued",CANCELED:"canceled",PAUSED:"paused",UPLOADING:"uploading",UPLOAD_RETRYING:"retrying upload",UPLOAD_SUCCESSFUL:"upload successful",UPLOAD_FAILED:"upload failed",DELETE_FAILED:"delete failed",DELETING:"deleting",DELETED:"deleted"},function(){"use strict";qq.basePublicApi={addBlobs:function(e,t,n){this.addFiles(e,t,n)},addInitialFiles:function(e){var t=this;qq.each(e,function(e,n){t._addCannedFile(n)})},addFiles:function(e,t,n){this._maybeHandleIos8SafariWorkaround();var i=0===this._storedIds.length?qq.getUniqueId():this._currentBatchId,r=qq.bind(function(e){this._handleNewFile({blob:e,name:this._options.blobs.defaultName},i,d)},this),o=qq.bind(function(e){this._handleNewFile(e,i,d)},this),a=qq.bind(function(e){var t=qq.canvasToBlob(e);this._handleNewFile({blob:t,name:this._options.blobs.defaultName+".png"},i,d)},this),s=qq.bind(function(e){var t=e.quality&&e.quality/100,n=qq.canvasToBlob(e.canvas,e.type,t);this._handleNewFile({blob:n,name:e.name},i,d)},this),u=qq.bind(function(e){if(qq.isInput(e)&&qq.supportedFeatures.ajaxUploading){var t=Array.prototype.slice.call(e.files),n=this;qq.each(t,function(e,t){n._handleNewFile(t,i,d)})}else this._handleNewFile(e,i,d)},this),c=function(){qq.isFileList(e)&&(e=Array.prototype.slice.call(e)),e=[].concat(e)},l=this,d=[];this._currentBatchId=i,e&&(c(),qq.each(e,function(e,t){qq.isFileOrInput(t)?u(t):qq.isBlob(t)?r(t):qq.isObject(t)?t.blob&&t.name?o(t):t.canvas&&t.name&&s(t):t.tagName&&"canvas"===t.tagName.toLowerCase()?a(t):l.log(t+" is not a valid file container! Ignoring!","warn")}),this.log("Received "+d.length+" files."),this._prepareItemsForUpload(d,t,n))},cancel:function(e){this._handler.cancel(e)},cancelAll:function(){var e=[],t=this;qq.extend(e,this._storedIds),qq.each(e,function(e,n){t.cancel(n)}),this._handler.cancelAll()},clearStoredFiles:function(){this._storedIds=[]},continueUpload:function(e){var t=this._uploadData.retrieve({id:e});return!(!qq.supportedFeatures.pause||!this._options.chunking.enabled)&&(t.status===qq.status.PAUSED?(this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.",e,this.getName(e))),this._uploadFile(e),!0):(this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.",e,this.getName(e)),"error"),!1))},deleteFile:function(e){return this._onSubmitDelete(e)},doesExist:function(e){return this._handler.isValid(e)},drawThumbnail:function(e,t,n,i,r){var o,a,s=new qq.Promise;return this._imageGenerator?(o=this._thumbnailUrls[e],a={customResizeFunction:r,maxSize:n>0?n:null,scale:n>0},!i&&qq.supportedFeatures.imagePreviews&&(o=this.getFile(e)),null==o?s.failure({container:t,error:"File or URL not found."}):this._imageGenerator.generate(o,t,a).then(function(e){s.success(e)},function(e,t){s.failure({container:e,error:t||"Problem generating thumbnail"})})):s.failure({container:t,error:"Missing image generator module"}),s},getButton:function(e){return this._getButton(this._buttonIdsForFileIds[e])},getEndpoint:function(e){return this._endpointStore.get(e)},getFile:function(e){return this._handler.getFile(e)||null},getInProgress:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED]}).length},getName:function(e){return this._uploadData.retrieve({id:e}).name},getParentId:function(e){var t=this.getUploads({id:e}),n=null;return t&&void 0!==t.parentId&&(n=t.parentId),n},getResumableFilesData:function(){return this._handler.getResumableFilesData()},getSize:function(e){return this._uploadData.retrieve({id:e}).size},getNetUploads:function(){return this._netUploaded},getRemainingAllowedItems:function(){var e=this._currentItemLimit;return e>0?e-this._netUploadedOrQueued:null},getUploads:function(e){return this._uploadData.retrieve(e)},getUuid:function(e){return this._uploadData.retrieve({id:e}).uuid},log:function(e,t){!this._options.debug||t&&"info"!==t?t&&"info"!==t&&qq.log("[Fine Uploader "+qq.version+"] "+e,t):qq.log("[Fine Uploader "+qq.version+"] "+e)},pauseUpload:function(e){var t=this._uploadData.retrieve({id:e});if(!qq.supportedFeatures.pause||!this._options.chunking.enabled)return!1;if(qq.indexOf([qq.status.UPLOADING,qq.status.UPLOAD_RETRYING],t.status)>=0){if(this._handler.pause(e))return this._uploadData.setStatus(e,qq.status.PAUSED),!0;this.log(qq.format("Unable to pause file ID {} ({}).",e,this.getName(e)),"error")}else this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.",e,this.getName(e)),"error");return!1},reset:function(){this.log("Resetting uploader..."),this._handler.reset(),this._storedIds=[],this._autoRetries=[],this._retryTimeouts=[],this._preventRetries=[],this._thumbnailUrls=[],qq.each(this._buttons,function(e,t){t.reset()}),this._paramsStore.reset(),this._endpointStore.reset(),this._netUploadedOrQueued=0,this._netUploaded=0,this._uploadData.reset(),this._buttonIdsForFileIds=[],this._pasteHandler&&this._pasteHandler.reset(),this._options.session.refreshOnReset&&this._refreshSessionData(),this._succeededSinceLastAllComplete=[],this._failedSinceLastAllComplete=[],this._totalProgress&&this._totalProgress.reset()},retry:function(e){return this._manualRetry(e)},scaleImage:function(e,t){var n=this;return qq.Scaler.prototype.scaleImage(e,t,{log:qq.bind(n.log,n),getFile:qq.bind(n.getFile,n),uploadData:n._uploadData})},setCustomHeaders:function(e,t){this._customHeadersStore.set(e,t)},setDeleteFileCustomHeaders:function(e,t){this._deleteFileCustomHeadersStore.set(e,t)},setDeleteFileEndpoint:function(e,t){this._deleteFileEndpointStore.set(e,t)},setDeleteFileParams:function(e,t){this._deleteFileParamsStore.set(e,t)},setEndpoint:function(e,t){this._endpointStore.set(e,t)},setForm:function(e){this._updateFormSupportAndParams(e)},setItemLimit:function(e){this._currentItemLimit=e},setName:function(e,t){this._uploadData.updateName(e,t)},setParams:function(e,t){this._paramsStore.set(e,t)},setUuid:function(e,t){return this._uploadData.uuidChanged(e,t)},uploadStoredFiles:function(){0===this._storedIds.length?this._itemError("noFilesError"):this._uploadStoredFiles()}},qq.basePrivateApi={_addCannedFile:function(e){var t=this._uploadData.addFile({uuid:e.uuid,name:e.name,size:e.size,status:qq.status.UPLOAD_SUCCESSFUL});return e.deleteFileEndpoint&&this.setDeleteFileEndpoint(e.deleteFileEndpoint,t),e.deleteFileParams&&this.setDeleteFileParams(e.deleteFileParams,t),e.thumbnailUrl&&(this._thumbnailUrls[t]=e.thumbnailUrl),this._netUploaded++,this._netUploadedOrQueued++,t},_annotateWithButtonId:function(e,t){qq.isFile(e)&&(e.qqButtonId=this._getButtonId(t))},_batchError:function(e){this._options.callbacks.onError(null,null,e,void 0)},_createDeleteHandler:function(){var e=this;return new qq.DeleteFileAjaxRequester({method:this._options.deleteFile.method.toUpperCase(),maxConnections:this._options.maxConnections,uuidParamName:this._options.request.uuidName,customHeaders:this._deleteFileCustomHeadersStore,paramsStore:this._deleteFileParamsStore,endpointStore:this._deleteFileEndpointStore,cors:this._options.cors,log:qq.bind(e.log,e),onDelete:function(t){e._onDelete(t),e._options.callbacks.onDelete(t)},onDeleteComplete:function(t,n,i){e._onDeleteComplete(t,n,i),e._options.callbacks.onDeleteComplete(t,n,i)}})},_createPasteHandler:function(){var e=this;return new qq.PasteSupport({targetElement:this._options.paste.targetElement,callbacks:{log:qq.bind(e.log,e),pasteReceived:function(t){e._handleCheckedCallback({name:"onPasteReceived",callback:qq.bind(e._options.callbacks.onPasteReceived,e,t),onSuccess:qq.bind(e._handlePasteSuccess,e,t),identifier:"pasted image"})}}})},_createStore:function(e,t){var n={},i=e,r={},o=t,a=function(e){return qq.isObject(e)?qq.extend({},e):e},s=function(){return qq.isFunction(o)?o():o},u=function(e,t){o&&qq.isObject(t)&&qq.extend(t,s()),r[e]&&qq.extend(t,r[e])};return{set:function(e,t){null==t?(n={},i=a(e)):n[t]=a(e)},get:function(e){var t;return t=null!=e&&n[e]?n[e]:a(i),u(e,t),a(t)},addReadOnly:function(e,t){qq.isObject(n)&&(null===e?qq.isFunction(t)?o=t:(o=o||{},qq.extend(o,t)):(r[e]=r[e]||{},qq.extend(r[e],t)))},remove:function(e){return delete n[e]},reset:function(){n={},r={},i=e}}},_createUploadDataTracker:function(){var e=this;return new qq.UploadData({getName:function(t){return e.getName(t)},getUuid:function(t){return e.getUuid(t)},getSize:function(t){return e.getSize(t)},onStatusChange:function(t,n,i){e._onUploadStatusChange(t,n,i),e._options.callbacks.onStatusChange(t,n,i),e._maybeAllComplete(t,i),e._totalProgress&&setTimeout(function(){e._totalProgress.onStatusChange(t,n,i)},0)}})},_createUploadButton:function(e){function t(){return!!qq.supportedFeatures.ajaxUploading&&(!(i._options.workarounds.iosEmptyVideos&&qq.ios()&&!qq.ios6()&&i._isAllowedExtension(o,".mov"))&&(void 0===e.multiple?i._options.multiple:e.multiple))}var n,i=this,r=e.accept||this._options.validation.acceptFiles,o=e.allowedExtensions||this._options.validation.allowedExtensions;return n=new qq.UploadButton({acceptFiles:r,element:e.element,focusClass:this._options.classes.buttonFocus,folders:e.folders,hoverClass:this._options.classes.buttonHover,ios8BrowserCrashWorkaround:this._options.workarounds.ios8BrowserCrash,multiple:t(),name:this._options.request.inputName,onChange:function(e){i._onInputChange(e)},title:null==e.title?this._options.text.fileInputTitle:e.title}),this._disposeSupport.addDisposer(function(){n.dispose()}),i._buttons.push(n),n},_createUploadHandler:function(e,t){var n=this,i={},r={debug:this._options.debug,maxConnections:this._options.maxConnections,cors:this._options.cors,paramsStore:this._paramsStore,endpointStore:this._endpointStore,chunking:this._options.chunking,resume:this._options.resume,blobs:this._options.blobs,log:qq.bind(n.log,n),preventRetryParam:this._options.retry.preventRetryResponseProperty,onProgress:function(e,t,r,o){r<0||o<0||(i[e]?i[e].loaded===r&&i[e].total===o||(n._onProgress(e,t,r,o),n._options.callbacks.onProgress(e,t,r,o)):(n._onProgress(e,t,r,o),n._options.callbacks.onProgress(e,t,r,o)),i[e]={loaded:r,total:o})},onComplete:function(e,t,r,o){delete i[e];var a,s=n.getUploads({id:e}).status;s!==qq.status.UPLOAD_SUCCESSFUL&&s!==qq.status.UPLOAD_FAILED&&(a=n._onComplete(e,t,r,o),a instanceof qq.Promise?a.done(function(){n._options.callbacks.onComplete(e,t,r,o)}):n._options.callbacks.onComplete(e,t,r,o))},onCancel:function(e,t,i){var r=new qq.Promise;return n._handleCheckedCallback({name:"onCancel",callback:qq.bind(n._options.callbacks.onCancel,n,e,t),onFailure:r.failure,onSuccess:function(){i.then(function(){n._onCancel(e,t)}),r.success()},identifier:e}),r},onUploadPrep:qq.bind(this._onUploadPrep,this),onUpload:function(e,t){n._onUpload(e,t),n._options.callbacks.onUpload(e,t)},onUploadChunk:function(e,t,i){n._onUploadChunk(e,i),n._options.callbacks.onUploadChunk(e,t,i)},onUploadChunkSuccess:function(e,t,i,r){n._options.callbacks.onUploadChunkSuccess.apply(n,arguments)},onResume:function(e,t,i){return n._options.callbacks.onResume(e,t,i)},onAutoRetry:function(e,t,i,r){return n._onAutoRetry.apply(n,arguments)},onUuidChanged:function(e,t){n.log("Server requested UUID change from '"+n.getUuid(e)+"' to '"+t+"'"),n.setUuid(e,t)},getName:qq.bind(n.getName,n),getUuid:qq.bind(n.getUuid,n),getSize:qq.bind(n.getSize,n),setSize:qq.bind(n._setSize,n),getDataByUuid:function(e){return n.getUploads({uuid:e})},isQueued:function(e){var t=n.getUploads({id:e}).status;return t===qq.status.QUEUED||t===qq.status.SUBMITTED||t===qq.status.UPLOAD_RETRYING||t===qq.status.PAUSED},getIdsInProxyGroup:n._uploadData.getIdsInProxyGroup,getIdsInBatch:n._uploadData.getIdsInBatch};return qq.each(this._options.request,function(e,t){r[e]=t}),r.customHeaders=this._customHeadersStore,e&&qq.each(e,function(e,t){r[e]=t}),new qq.UploadHandlerController(r,t)},_fileOrBlobRejected:function(e){this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.REJECTED)},_formatSize:function(e){if(0===e)return e+this._options.text.sizeSymbols[0];var t=-1;do e/=1e3,t++;while(e>999);return Math.max(e,.1).toFixed(1)+this._options.text.sizeSymbols[t]},_generateExtraButtonSpecs:function(){var e=this;this._extraButtonSpecs={},qq.each(this._options.extraButtons,function(t,n){var i=n.multiple,r=qq.extend({},e._options.validation,!0),o=qq.extend({},n);void 0===i&&(i=e._options.multiple),o.validation&&qq.extend(r,n.validation,!0),qq.extend(o,{multiple:i,validation:r},!0),e._initExtraButton(o)})},_getButton:function(e){var t=this._extraButtonSpecs[e];return t?t.element:e===this._defaultButtonId?this._options.button:void 0},_getButtonId:function(e){var t,n,i=e;if(i instanceof qq.BlobProxy&&(i=i.referenceBlob),i&&!qq.isBlob(i)){if(qq.isFile(i))return i.qqButtonId;if("input"===i.tagName.toLowerCase()&&"file"===i.type.toLowerCase())return i.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);if(t=i.getElementsByTagName("input"),qq.each(t,function(e,t){if("file"===t.getAttribute("type"))return n=t,!1}),n)return n.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME)}},_getNotFinished:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED,qq.status.SUBMITTING,qq.status.SUBMITTED,qq.status.PAUSED]}).length},_getValidationBase:function(e){var t=this._extraButtonSpecs[e];return t?t.validation:this._options.validation},_getValidationDescriptor:function(e){return e.file instanceof qq.BlobProxy?{name:qq.getFilename(e.file.referenceBlob),size:e.file.referenceBlob.size}:{name:this.getUploads({id:e.id}).name,size:this.getUploads({id:e.id}).size}},_getValidationDescriptors:function(e){var t=this,n=[];return qq.each(e,function(e,i){n.push(t._getValidationDescriptor(i))}),n},_handleCameraAccess:function(){if(this._options.camera.ios&&qq.ios()){var e="image/*;capture=camera",t=this._options.camera.button,n=t?this._getButtonId(t):this._defaultButtonId,i=this._options;n&&n!==this._defaultButtonId&&(i=this._extraButtonSpecs[n]),i.multiple=!1,null===i.validation.acceptFiles?i.validation.acceptFiles=e:i.validation.acceptFiles+=","+e,qq.each(this._buttons,function(e,t){if(t.getButtonId()===n)return t.setMultiple(i.multiple),t.setAcceptFiles(i.acceptFiles),!1})}},_handleCheckedCallback:function(e){var t=this,n=e.callback();return qq.isGenericPromise(n)?(this.log(e.name+" - waiting for "+e.name+" promise to be fulfilled for "+e.identifier),n.then(function(n){t.log(e.name+" promise success for "+e.identifier),e.onSuccess(n)},function(){e.onFailure?(t.log(e.name+" promise failure for "+e.identifier),e.onFailure()):t.log(e.name+" promise failure for "+e.identifier)})):(n!==!1?e.onSuccess(n):e.onFailure?(this.log(e.name+" - return value was 'false' for "+e.identifier+". Invoking failure callback."),e.onFailure()):this.log(e.name+" - return value was 'false' for "+e.identifier+". Will not proceed."),n)},_handleNewFile:function(e,t,n){var i=this,r=qq.getUniqueId(),o=-1,a=qq.getFilename(e),s=e.blob||e,u=this._customNewFileHandler?this._customNewFileHandler:qq.bind(i._handleNewFileGeneric,i);!qq.isInput(s)&&s.size>=0&&(o=s.size),u(s,a,r,o,n,t,this._options.request.uuidName,{uploadData:i._uploadData,paramsStore:i._paramsStore,addFileToHandler:function(e,t){i._handler.add(e,t),i._netUploadedOrQueued++,
+i._trackButton(e)}})},_handleNewFileGeneric:function(e,t,n,i,r,o){var a=this._uploadData.addFile({uuid:n,name:t,size:i,batchId:o});this._handler.add(a,e),this._trackButton(a),this._netUploadedOrQueued++,r.push({id:a,file:e})},_handlePasteSuccess:function(e,t){var n=e.type.split("/")[1],i=t;null==i&&(i=this._options.paste.defaultName),i+="."+n,this.addFiles({name:i,blob:e})},_initExtraButton:function(e){var t=this._createUploadButton({accept:e.validation.acceptFiles,allowedExtensions:e.validation.allowedExtensions,element:e.element,folders:e.folders,multiple:e.multiple,title:e.fileInputTitle});this._extraButtonSpecs[t.getButtonId()]=e},_initFormSupportAndParams:function(){this._formSupport=qq.FormSupport&&new qq.FormSupport(this._options.form,qq.bind(this.uploadStoredFiles,this),qq.bind(this.log,this)),this._formSupport&&this._formSupport.attachedToForm?(this._paramsStore=this._createStore(this._options.request.params,this._formSupport.getFormInputsAsObject),this._options.autoUpload=this._formSupport.newAutoUpload,this._formSupport.newEndpoint&&(this._options.request.endpoint=this._formSupport.newEndpoint)):this._paramsStore=this._createStore(this._options.request.params)},_isDeletePossible:function(){return!(!qq.DeleteFileAjaxRequester||!this._options.deleteFile.enabled)&&(!this._options.cors.expected||(!!qq.supportedFeatures.deleteFileCorsXhr||!(!qq.supportedFeatures.deleteFileCorsXdr||!this._options.cors.allowXdr)))},_isAllowedExtension:function(e,t){var n=!1;return!e.length||(qq.each(e,function(e,i){if(qq.isString(i)){var r=new RegExp("\\."+i+"$","i");if(null!=t.match(r))return n=!0,!1}}),n)},_itemError:function(e,t,n){function i(e,t){a=a.replace(e,t)}var r,o,a=this._options.messages[e],s=[],u=[].concat(t),c=u[0],l=this._getButtonId(n),d=this._getValidationBase(l);return qq.each(d.allowedExtensions,function(e,t){qq.isString(t)&&s.push(t)}),r=s.join(", ").toLowerCase(),i("{file}",this._options.formatFileName(c)),i("{extensions}",r),i("{sizeLimit}",this._formatSize(d.sizeLimit)),i("{minSizeLimit}",this._formatSize(d.minSizeLimit)),o=a.match(/(\{\w+\})/g),null!==o&&qq.each(o,function(e,t){i(t,u[e])}),this._options.callbacks.onError(null,c,a,void 0),a},_manualRetry:function(e,t){if(this._onBeforeManualRetry(e))return this._netUploadedOrQueued++,this._uploadData.setStatus(e,qq.status.UPLOAD_RETRYING),t?t(e):this._handler.retry(e),!0},_maybeAllComplete:function(e,t){var n=this,i=this._getNotFinished();t===qq.status.UPLOAD_SUCCESSFUL?this._succeededSinceLastAllComplete.push(e):t===qq.status.UPLOAD_FAILED&&this._failedSinceLastAllComplete.push(e),0===i&&(this._succeededSinceLastAllComplete.length||this._failedSinceLastAllComplete.length)&&setTimeout(function(){n._onAllComplete(n._succeededSinceLastAllComplete,n._failedSinceLastAllComplete)},0)},_maybeHandleIos8SafariWorkaround:function(){var e=this;if(this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari())throw setTimeout(function(){window.alert(e._options.messages.unsupportedBrowserIos8Safari)},0),new qq.Error(this._options.messages.unsupportedBrowserIos8Safari)},_maybeParseAndSendUploadError:function(e,t,n,i){if(!n.success)if(i&&200!==i.status&&!n.error)this._options.callbacks.onError(e,t,"XHR returned response code "+i.status,i);else{var r=n.error?n.error:this._options.text.defaultResponseError;this._options.callbacks.onError(e,t,r,i)}},_maybeProcessNextItemAfterOnValidateCallback:function(e,t,n,i,r){var o=this;if(t.length>n)if(e||!this._options.validation.stopOnFirstInvalidFile)setTimeout(function(){var e=o._getValidationDescriptor(t[n]),a=o._getButtonId(t[n].file),s=o._getButton(a);o._handleCheckedCallback({name:"onValidate",callback:qq.bind(o._options.callbacks.onValidate,o,e,s),onSuccess:qq.bind(o._onValidateCallbackSuccess,o,t,n,i,r),onFailure:qq.bind(o._onValidateCallbackFailure,o,t,n,i,r),identifier:"Item '"+e.name+"', size: "+e.size})},0);else if(!e)for(;n0&&this._netUploadedOrQueued+1>n?(this._itemError("retryFailTooManyItems"),!1):(this.log("Retrying upload for '"+t+"' (id: "+e+")..."),!0))):(this.log("'"+e+"' is not a valid file ID","error"),!1)},_onCancel:function(e,t){this._netUploadedOrQueued--,clearTimeout(this._retryTimeouts[e]);var n=qq.indexOf(this._storedIds,e);!this._options.autoUpload&&n>=0&&this._storedIds.splice(n,1),this._uploadData.setStatus(e,qq.status.CANCELED)},_onComplete:function(e,t,n,i){return n.success?(n.thumbnailUrl&&(this._thumbnailUrls[e]=n.thumbnailUrl),this._netUploaded++,this._uploadData.setStatus(e,qq.status.UPLOAD_SUCCESSFUL)):(this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.UPLOAD_FAILED),n[this._options.retry.preventRetryResponseProperty]===!0&&(this._preventRetries[e]=!0)),this._maybeParseAndSendUploadError(e,t,n,i),!!n.success},_onDelete:function(e){this._uploadData.setStatus(e,qq.status.DELETING)},_onDeleteComplete:function(e,t,n){var i=this.getName(e);n?(this._uploadData.setStatus(e,qq.status.DELETE_FAILED),this.log("Delete request for '"+i+"' has failed.","error"),void 0===t.withCredentials?this._options.callbacks.onError(e,i,"Delete request failed",t):this._options.callbacks.onError(e,i,"Delete request failed with response code "+t.status,t)):(this._netUploadedOrQueued--,this._netUploaded--,this._handler.expunge(e),this._uploadData.setStatus(e,qq.status.DELETED),this.log("Delete request for '"+i+"' has succeeded."))},_onInputChange:function(e){var t;if(qq.supportedFeatures.ajaxUploading){for(t=0;t0&&this.addFiles(e);qq.each(this._buttons,function(e,t){t.reset()})},_onProgress:function(e,t,n,i){this._totalProgress&&this._totalProgress.onIndividualProgress(e,n,i)},_onSubmit:function(e,t){},_onSubmitCallbackSuccess:function(e,t){this._onSubmit.apply(this,arguments),this._uploadData.setStatus(e,qq.status.SUBMITTED),this._onSubmitted.apply(this,arguments),this._options.autoUpload?(this._options.callbacks.onSubmitted.apply(this,arguments),this._uploadFile(e)):(this._storeForLater(e),this._options.callbacks.onSubmitted.apply(this,arguments))},_onSubmitDelete:function(e,t,n){var i,r=this.getUuid(e);return t&&(i=qq.bind(t,this,e,r,n)),this._isDeletePossible()?(this._handleCheckedCallback({name:"onSubmitDelete",callback:qq.bind(this._options.callbacks.onSubmitDelete,this,e),onSuccess:i||qq.bind(this._deleteHandler.sendDelete,this,e,r,n),identifier:e}),!0):(this.log("Delete request ignored for ID "+e+", delete feature is disabled or request not possible due to CORS on a user agent that does not support pre-flighting.","warn"),!1)},_onSubmitted:function(e){},_onTotalProgress:function(e,t){this._options.callbacks.onTotalProgress(e,t)},_onUploadPrep:function(e){},_onUpload:function(e,t){this._uploadData.setStatus(e,qq.status.UPLOADING)},_onUploadChunk:function(e,t){},_onUploadStatusChange:function(e,t,n){n===qq.status.PAUSED&&clearTimeout(this._retryTimeouts[e])},_onValidateBatchCallbackFailure:function(e){var t=this;qq.each(e,function(e,n){t._fileOrBlobRejected(n.id)})},_onValidateBatchCallbackSuccess:function(e,t,n,i,r){var o,a=this._currentItemLimit,s=this._netUploadedOrQueued;0===a||s<=a?t.length>0?this._handleCheckedCallback({name:"onValidate",callback:qq.bind(this._options.callbacks.onValidate,this,e[0],r),onSuccess:qq.bind(this._onValidateCallbackSuccess,this,t,0,n,i),onFailure:qq.bind(this._onValidateCallbackFailure,this,t,0,n,i),identifier:"Item '"+t[0].file.name+"', size: "+t[0].file.size}):this._itemError("noFilesError"):(this._onValidateBatchCallbackFailure(t),o=this._options.messages.tooManyItemsError.replace(/\{netItems\}/g,s).replace(/\{itemLimit\}/g,a),this._batchError(o))},_onValidateCallbackFailure:function(e,t,n,i){var r=t+1;this._fileOrBlobRejected(e[t].id,e[t].file.name),this._maybeProcessNextItemAfterOnValidateCallback(!1,e,r,n,i)},_onValidateCallbackSuccess:function(e,t,n,i){var r=this,o=t+1,a=this._getValidationDescriptor(e[t]);this._validateFileOrBlobData(e[t],a).then(function(){r._upload(e[t].id,n,i),r._maybeProcessNextItemAfterOnValidateCallback(!0,e,o,n,i)},function(){r._maybeProcessNextItemAfterOnValidateCallback(!1,e,o,n,i)})},_prepareItemsForUpload:function(e,t,n){if(0===e.length)return void this._itemError("noFilesError");var i=this._getValidationDescriptors(e),r=this._getButtonId(e[0].file),o=this._getButton(r);this._handleCheckedCallback({name:"onValidateBatch",callback:qq.bind(this._options.callbacks.onValidateBatch,this,i,o),onSuccess:qq.bind(this._onValidateBatchCallbackSuccess,this,i,e,t,n,o),onFailure:qq.bind(this._onValidateBatchCallbackFailure,this,e),identifier:"batch validation"})},_preventLeaveInProgress:function(){var e=this;this._disposeSupport.attach(window,"beforeunload",function(t){if(e.getInProgress())return t=t||window.event,t.returnValue=e._options.messages.onLeave,e._options.messages.onLeave})},_refreshSessionData:function(){var e=this,t=this._options.session;qq.Session&&null!=this._options.session.endpoint&&(this._session||(qq.extend(t,{cors:this._options.cors}),t.log=qq.bind(this.log,this),t.addFileRecord=qq.bind(this._addCannedFile,this),this._session=new qq.Session(t)),setTimeout(function(){e._session.refresh().then(function(t,n){e._sessionRequestComplete(),e._options.callbacks.onSessionRequestComplete(t,!0,n)},function(t,n){e._options.callbacks.onSessionRequestComplete(t,!1,n)})},0))},_sessionRequestComplete:function(){},_setSize:function(e,t){this._uploadData.updateSize(e,t),this._totalProgress&&this._totalProgress.onNewSize(e)},_shouldAutoRetry:function(e,t,n){var i=this._uploadData.retrieve({id:e});return!!(!this._preventRetries[e]&&this._options.retry.enableAuto&&i.status!==qq.status.PAUSED&&(void 0===this._autoRetries[e]&&(this._autoRetries[e]=0),this._autoRetries[e]0&&s.sizeLimit&&o>s.sizeLimit?(this._itemError("sizeError",r,i),u.failure()):o>0&&o=0}function n(e){var t=!1;return qq.each(t,function(e,n){if(qq.indexOf(["Accept","Accept-Language","Content-Language","Content-Type"],n)<0)return t=!0,!1}),t}function i(e){return y.cors.expected&&void 0===e.withCredentials}function r(){var e;return(window.XMLHttpRequest||window.ActiveXObject)&&(e=qq.createXhrInstance(),void 0===e.withCredentials&&(e=new XDomainRequest,e.onload=function(){},e.onerror=function(){},e.ontimeout=function(){},e.onprogress=function(){})),e}function o(e,t){var n=v[e].xhr;return n||(n=t?t:y.cors.expected?r():qq.createXhrInstance(),v[e].xhr=n),n}function a(e){var t,n=qq.indexOf(b,e),i=y.maxConnections;delete v[e],b.splice(n,1),b.length>=i&&n=0?r.send(qq.obj2url(s,"")):s&&y.contentType&&y.contentType.toLowerCase().indexOf("application/json")>=0?r.send(JSON.stringify(s)):r.send(s),r}function l(e,t,n){var i=y.endpointStore.get(e),r=v[e].addToPath;return void 0!=r&&(i+="/"+r),S&&t&&(i=qq.obj2url(t,i)),n&&(i=qq.obj2url(n,i)),i}function d(e){return function(){4===o(e).readyState&&s(e)}}function p(e){var t=y.onProgress;t&&(o(e).upload.onprogress=function(n){n.lengthComputable&&t(e,n.loaded,n.total)})}function q(e){return function(){s(e)}}function f(e){return function(){s(e,!0)}}function h(e){var r=o(e),a=y.customHeaders,s=v[e].additionalHeaders||{},u=y.method,c={};i(r)||(y.acceptHeader&&r.setRequestHeader("Accept",y.acceptHeader),y.allowXRequestedWithAndCacheControl&&(y.cors.expected&&t()&&!n(a)||(r.setRequestHeader("X-Requested-With","XMLHttpRequest"),r.setRequestHeader("Cache-Control","no-cache"))),!y.contentType||"POST"!==u&&"PUT"!==u||r.setRequestHeader("Content-Type",y.contentType),qq.extend(c,qq.isFunction(a)?a(e):a),qq.extend(c,s),qq.each(c,function(e,t){r.setRequestHeader(e,t)}))}function g(e){return qq.indexOf(y.successfulResponseCodes[y.method],e)>=0}function m(e,t,n,i,r,o,a){v[e]={addToPath:n,additionalParams:i,additionalQueryParams:r,additionalHeaders:o,payload:a};var s=b.push(e);if(s<=y.maxConnections)return c(e,t)}var _,S,b=[],v={},y={acceptHeader:null,validMethods:["PATCH","POST","PUT"],method:"POST",contentType:"application/x-www-form-urlencoded",maxConnections:3,customHeaders:{},endpointStore:{},paramsStore:{},mandatedParams:{},allowXRequestedWithAndCacheControl:!0,successfulResponseCodes:{DELETE:[200,202,204],PATCH:[200,201,202,203,204],POST:[200,201,202,203,204],PUT:[200,201,202,203,204],GET:[200]},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onSend:function(e){},onComplete:function(e,t,n){},onProgress:null};if(qq.extend(y,e),_=y.log,qq.indexOf(y.validMethods,y.method)<0)throw new Error("'"+y.method+"' is not a supported method for this type of request!");S="GET"===y.method||"DELETE"===y.method,qq.extend(this,{initTransport:function(e){var t,n,i,r,o,a;return{withPath:function(e){return t=e,this},withParams:function(e){return n=e,this},withQueryParams:function(e){return a=e,this},withHeaders:function(e){return i=e,this},withPayload:function(e){return r=e,this},withCacheBuster:function(){return o=!0,this},send:function(s){return o&&qq.indexOf(["GET","DELETE"],y.method)>=0&&(n.qqtimestamp=(new Date).getTime()),m(e,s,t,n,a,i,r)}}},canceled:function(e){a(e)}})},qq.UploadHandler=function(e){"use strict";var t=e.proxy,n={},i=t.onCancel,r=t.getName;qq.extend(this,{add:function(e,t){n[e]=t,n[e].temp={}},cancel:function(e){var t=this,o=new qq.Promise,a=i(e,r(e),o);a.then(function(){t.isValid(e)&&(n[e].canceled=!0,t.expunge(e)),o.success()})},expunge:function(e){delete n[e]},getThirdPartyFileId:function(e){return n[e].key},isValid:function(e){return void 0!==n[e]},reset:function(){n={}},_getFileState:function(e){return n[e]},_setThirdPartyFileId:function(e,t){n[e].key=t},_wasCanceled:function(e){return!!n[e].canceled}})},qq.UploadHandlerController=function(e,t){"use strict";var n,i,r,o=this,a=!1,s=!1,u={paramsStore:{},maxConnections:3,chunking:{enabled:!1,multiple:{enabled:!1}},log:function(e,t){},onProgress:function(e,t,n,i){},onComplete:function(e,t,n,i){},onCancel:function(e,t){},onUploadPrep:function(e){},onUpload:function(e,t){},onUploadChunk:function(e,t,n){},onUploadChunkSuccess:function(e,t,n,i){},onAutoRetry:function(e,t,n,i){},onResume:function(e,t,n){},onUuidChanged:function(e,t){},getName:function(e){},setSize:function(e,t){},isQueued:function(e){},getIdsInProxyGroup:function(e){},getIdsInBatch:function(e){}},c={done:function(e,t,n,i){var o=r._getChunkData(e,t);r._getFileState(e).attemptingResume=!1,delete r._getFileState(e).temp.chunkProgress[t],r._getFileState(e).loaded+=o.size,u.onUploadChunkSuccess(e,r._getChunkDataForCallback(o),n,i)},finalize:function(e){var t=u.getSize(e),n=u.getName(e);i("All chunks have been uploaded for "+e+" - finalizing...."),r.finalizeChunks(e).then(function(o,a){i("Finalize successful for "+e);var s=p.normalizeResponse(o,!0);u.onProgress(e,n,t,t),r._maybeDeletePersistedChunkData(e),p.cleanup(e,s,a)},function(t,r){var o=p.normalizeResponse(t,!1);i("Problem finalizing chunks for file ID "+e+" - "+o.error,"error"),o.reset&&c.reset(e),u.onAutoRetry(e,n,o,r)||p.cleanup(e,o,r)})},handleFailure:function(e,t,n,o){var a=u.getName(t);i("Chunked upload request failed for "+t+", chunk "+e),r.clearCachedChunk(t,e);var d,q=p.normalizeResponse(n,!1);q.reset?c.reset(t):(d=qq.indexOf(r._getFileState(t).chunking.inProgress,e),d>=0&&(r._getFileState(t).chunking.inProgress.splice(d,1),r._getFileState(t).chunking.remaining.unshift(e))),r._getFileState(t).temp.ignoreFailure||(s&&(r._getFileState(t).temp.ignoreFailure=!0,i(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.",JSON.stringify(Object.keys(r._getXhrs(t))),JSON.stringify(r._getFileState(t).chunking.inProgress))),qq.each(r._getXhrs(t),function(e,n){i(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ",t,e,n.readyState)),n.abort(),n._cancelled=!0}),r.moveInProgressToRemaining(t),l.free(t,!0)),u.onAutoRetry(t,a,q,o)||p.cleanup(t,q,o))},hasMoreParts:function(e){return!!r._getFileState(e).chunking.remaining.length},nextPart:function(e){var t=r._getFileState(e).chunking.remaining.shift();return t>=r._getTotalChunks(e)&&(t=null),t},reset:function(e){i("Server or callback has ordered chunking effort to be restarted on next attempt for item ID "+e,"error"),r._maybeDeletePersistedChunkData(e),r.reevaluateChunking(e),r._getFileState(e).loaded=0},sendNext:function(e){var t=u.getSize(e),n=u.getName(e),o=c.nextPart(e),a=r._getChunkData(e,o),d=r._getFileState(e).attemptingResume,q=r._getFileState(e).chunking.inProgress||[];null==r._getFileState(e).loaded&&(r._getFileState(e).loaded=0),d&&u.onResume(e,n,a)===!1&&(c.reset(e),o=c.nextPart(e),a=r._getChunkData(e,o),d=!1),null==o&&0===q.length?c.finalize(e):(i(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.",e,o,a.start+1,a.end,t)),u.onUploadChunk(e,n,r._getChunkDataForCallback(a)),q.push(o),r._getFileState(e).chunking.inProgress=q,s&&l.open(e,o),s&&l.available()&&r._getFileState(e).chunking.remaining.length&&c.sendNext(e),0===a.blob.size?(i(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.",o,e),"error"),c.handleFailure(o,e,"File is no longer available",null)):r.uploadChunk(e,o,d).then(function(t,n){i("Chunked upload request succeeded for "+e+", chunk "+o),r.clearCachedChunk(e,o);var a=r._getFileState(e).chunking.inProgress||[],s=p.normalizeResponse(t,!0),u=qq.indexOf(a,o);i(qq.format("Chunk {} for file {} uploaded successfully.",o,e)),c.done(e,o,s,n),u>=0&&a.splice(u,1),r._maybePersistChunkedState(e),c.hasMoreParts(e)||0!==a.length?c.hasMoreParts(e)?c.sendNext(e):i(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}",e,JSON.stringify(a))):c.finalize(e)},function(t,n){c.handleFailure(o,e,t,n)}).done(function(){r.clearXhr(e,o)}))}},l={_open:[],_openChunks:{},_waiting:[],available:function(){var e=u.maxConnections,t=0,n=0;return qq.each(l._openChunks,function(e,i){t++,n+=i.length}),e-(l._open.length-t+n)},free:function(e,t){var n,o=!t,a=qq.indexOf(l._waiting,e),s=qq.indexOf(l._open,e);delete l._openChunks[e],p.getProxyOrBlob(e)instanceof qq.BlobProxy&&(i("Generated blob upload has ended for "+e+", disposing generated blob."),delete r._getFileState(e).file),a>=0?l._waiting.splice(a,1):o&&s>=0&&(l._open.splice(s,1),n=l._waiting.shift(),n>=0&&(l._open.push(n),p.start(n)))},getWaitingOrConnected:function(){var e=[];return qq.each(l._openChunks,function(t,n){n&&n.length&&e.push(parseInt(t))}),qq.each(l._open,function(t,n){l._openChunks[n]||e.push(parseInt(n))}),e=e.concat(l._waiting)},isUsingConnection:function(e){return qq.indexOf(l._open,e)>=0},open:function(e,t){return null==t&&l._waiting.push(e),!!l.available()&&(null==t?(l._waiting.pop(),l._open.push(e)):!function(){var n=l._openChunks[e]||[];n.push(t),l._openChunks[e]=n}(),!0)},reset:function(){l._waiting=[],l._open=[]}},d={send:function(e,t){r._getFileState(e).loaded=0,i("Sending simple upload request for "+e),r.uploadFile(e).then(function(n,r){i("Simple upload request succeeded for "+e);var o=p.normalizeResponse(n,!0),a=u.getSize(e);u.onProgress(e,t,a,a),p.maybeNewUuid(e,o),p.cleanup(e,o,r)},function(n,r){i("Simple upload request failed for "+e);var o=p.normalizeResponse(n,!1);u.onAutoRetry(e,t,o,r)||p.cleanup(e,o,r)})}},p={cancel:function(e){i("Cancelling "+e),u.paramsStore.remove(e),l.free(e)},cleanup:function(e,t,n){var i=u.getName(e);u.onComplete(e,i,t,n),r._getFileState(e)&&r._clearXhrs&&r._clearXhrs(e),l.free(e)},getProxyOrBlob:function(e){return r.getProxy&&r.getProxy(e)||r.getFile&&r.getFile(e)},initHandler:function(){var e=t?qq[t]:qq.traditional,n=qq.supportedFeatures.ajaxUploading?"Xhr":"Form";r=new e[n+"UploadHandler"](u,{getDataByUuid:u.getDataByUuid,getName:u.getName,getSize:u.getSize,getUuid:u.getUuid,log:i,onCancel:u.onCancel,onProgress:u.onProgress,onUuidChanged:u.onUuidChanged}),r._removeExpiredChunkingRecords&&r._removeExpiredChunkingRecords()},isDeferredEligibleForUpload:function(e){return u.isQueued(e)},maybeDefer:function(e,t){return t&&!r.getFile(e)&&t instanceof qq.BlobProxy?(u.onUploadPrep(e),i("Attempting to generate a blob on-demand for "+e),t.create().then(function(t){i("Generated an on-demand blob for "+e),r.updateBlob(e,t),u.setSize(e,t.size),r.reevaluateChunking(e),p.maybeSendDeferredFiles(e)},function(t){var r={};t&&(r.error=t),i(qq.format("Failed to generate blob for ID {}. Error message: {}.",e,t),"error"),u.onComplete(e,u.getName(e),qq.extend(r,n),null),p.maybeSendDeferredFiles(e),l.free(e)}),!1):p.maybeSendDeferredFiles(e)},maybeSendDeferredFiles:function(e){var t=u.getIdsInProxyGroup(e),n=!1;return t&&t.length?(i("Maybe ready to upload proxy group file "+e),qq.each(t,function(t,i){if(p.isDeferredEligibleForUpload(i)&&r.getFile(i))n=i===e,p.now(i);else if(p.isDeferredEligibleForUpload(i))return!1})):(n=!0,p.now(e)),n},maybeNewUuid:function(e,t){void 0!==t.newUuid&&u.onUuidChanged(e,t.newUuid)},normalizeResponse:function(e,t){var n=e;return qq.isObject(e)||(n={},qq.isString(e)&&!t&&(n.error=e)),n.success=t,n},now:function(e){var t=u.getName(e);if(!o.isValid(e))throw new qq.Error(e+" is not a valid file ID to upload!");u.onUpload(e,t),a&&r._shouldChunkThisFile(e)?c.sendNext(e):d.send(e,t)},start:function(e){var t=p.getProxyOrBlob(e);return t?p.maybeDefer(e,t):(p.now(e),!0)}};qq.extend(this,{add:function(e,t){r.add.apply(this,arguments)},upload:function(e){return!!l.open(e)&&p.start(e)},retry:function(e){return s&&(r._getFileState(e).temp.ignoreFailure=!1),l.isUsingConnection(e)?p.start(e):o.upload(e)},cancel:function(e){var t=r.cancel(e);qq.isGenericPromise(t)?t.then(function(){p.cancel(e)}):t!==!1&&p.cancel(e)},cancelAll:function(){var e,t=l.getWaitingOrConnected();if(t.length)for(e=t.length-1;e>=0;e--)o.cancel(t[e]);l.reset()},getFile:function(e){return r.getProxy&&r.getProxy(e)?r.getProxy(e).referenceBlob:r.getFile&&r.getFile(e);
+},isProxied:function(e){return!(!r.getProxy||!r.getProxy(e))},getInput:function(e){if(r.getInput)return r.getInput(e)},reset:function(){i("Resetting upload handler"),o.cancelAll(),l.reset(),r.reset()},expunge:function(e){if(o.isValid(e))return r.expunge(e)},isValid:function(e){return r.isValid(e)},getResumableFilesData:function(){return r.getResumableFilesData?r.getResumableFilesData():[]},getThirdPartyFileId:function(e){if(o.isValid(e))return r.getThirdPartyFileId(e)},pause:function(e){return!!(o.isResumable(e)&&r.pause&&o.isValid(e)&&r.pause(e))&&(l.free(e),r.moveInProgressToRemaining(e),!0)},isResumable:function(e){return!!r.isResumable&&r.isResumable(e)}}),qq.extend(u,e),i=u.log,a=u.chunking.enabled&&qq.supportedFeatures.chunking,s=a&&u.chunking.concurrent.enabled,n=function(){var e={};return e[u.preventRetryParam]=!0,e}(),p.initHandler()},qq.WindowReceiveMessage=function(e){"use strict";var t={log:function(e,t){}},n={};qq.extend(t,e),qq.extend(this,{receiveMessage:function(e,t){var i=function(e){t(e.data)};window.postMessage?n[e]=qq(window).attach("message",i):log("iframe message passing not supported in this browser!","error")},stopReceivingMessages:function(e){if(window.postMessage){var t=n[e];t&&t()}}})},qq.FormUploadHandler=function(e){"use strict";function t(e){delete l[e],p&&(clearTimeout(d[e]),delete d[e],g.stopReceivingMessages(e));var t=document.getElementById(a._getIframeName(e));t&&(t.setAttribute("src","javascript:false;"),qq(t).remove())}function n(e){return e.split("_")[0]}function i(e){var t=qq.toElement("");return t.setAttribute("id",e),t.style.display="none",document.body.appendChild(t),t}function r(e,t){var i=e.id,r=n(i),o=f(r);c[o]=t,l[r]=qq(e).attach("load",function(){a.getInput(r)&&(h("Received iframe load event for CORS upload request (iframe name "+i+")"),d[i]=setTimeout(function(){var e="No valid message received from loaded iframe for iframe name "+i;h(e,"error"),t({error:e})},1e3))}),g.receiveMessage(i,function(e){h("Received the following window message: '"+e+"'");var t,r=(n(i),a._parseJsonResponse(e)),o=r.uuid;o&&c[o]?(h("Handling response for iframe name "+i),clearTimeout(d[i]),delete d[i],a._detachLoadEvent(i),t=c[o],delete c[o],g.stopReceivingMessages(i),t(r)):o||h("'"+e+"' does not contain a UUID - ignoring.")})}var o=e.options,a=this,s=e.proxy,u=qq.getUniqueId(),c={},l={},d={},p=o.isCors,q=o.inputName,f=s.getUuid,h=s.log,g=new qq.WindowReceiveMessage({log:h});qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,n){e.add(t,{input:n}),n.setAttribute("name",q),n.parentNode&&qq(n).remove()},expunge:function(n){t(n),e.expunge(n)},isValid:function(t){return e.isValid(t)&&void 0!==a._getFileState(t).input}}}),qq.extend(this,{getInput:function(e){return a._getFileState(e).input},_attachLoadEvent:function(e,t){var n;p?r(e,t):l[e.id]=qq(e).attach("load",function(){if(h("Received response for "+e.id),e.parentNode){try{if(e.contentDocument&&e.contentDocument.body&&"false"==e.contentDocument.body.innerHTML)return}catch(e){h("Error when attempting to access iframe during handling of upload response ("+e.message+")","error"),n={success:!1}}t(n)}})},_createIframe:function(e){var t=a._getIframeName(e);return i(t)},_detachLoadEvent:function(e){void 0!==l[e]&&(l[e](),delete l[e])},_getIframeName:function(e){return e+"_"+u},_initFormForUpload:function(e){var t=e.method,n=e.endpoint,i=e.params,r=e.paramsInBody,o=e.targetName,a=qq.toElement(""),s=n;return r?qq.obj2Inputs(i,a):s=qq.obj2url(i,n),a.setAttribute("action",s),a.setAttribute("target",o),a.style.display="none",document.body.appendChild(a),a},_parseJsonResponse:function(e){var t={};try{t=qq.parseJson(e)}catch(e){h("Error when attempting to parse iframe upload response ("+e.message+")","error")}return t}})},qq.XhrUploadHandler=function(e){"use strict";function t(e){qq.each(n._getXhrs(e),function(t,i){var r=n._getAjaxRequester(e,t);i.onreadystatechange=null,i.upload.onprogress=null,i.abort(),r&&r.canceled&&r.canceled(e)})}var n=this,i=e.options.namespace,r=e.proxy,o=e.options.chunking,a=e.options.resume,s=o&&e.options.chunking.enabled&&qq.supportedFeatures.chunking,u=a&&e.options.resume.enabled&&s&&qq.supportedFeatures.resume,c=r.getName,l=r.getSize,d=r.getUuid,p=r.getEndpoint,q=r.getDataByUuid,f=r.onUuidChanged,h=r.onProgress,g=r.log;qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,i){if(qq.isFile(i)||qq.isBlob(i))e.add(t,{file:i});else{if(!(i instanceof qq.BlobProxy))throw new Error("Passed obj is not a File, Blob, or proxy");e.add(t,{proxy:i})}n._initTempState(t),u&&n._maybePrepareForResume(t)},expunge:function(i){t(i),n._maybeDeletePersistedChunkData(i),n._clearXhrs(i),e.expunge(i)}}}),qq.extend(this,{clearCachedChunk:function(e,t){delete n._getFileState(e).temp.cachedChunks[t]},clearXhr:function(e,t){var i=n._getFileState(e).temp;i.xhrs&&delete i.xhrs[t],i.ajaxRequesters&&delete i.ajaxRequesters[t]},finalizeChunks:function(e,t){var i=n._getTotalChunks(e)-1,r=n._getXhr(e,i);return t?(new qq.Promise).success(t(r),r):(new qq.Promise).success({},r)},getFile:function(e){return n.isValid(e)&&n._getFileState(e).file},getProxy:function(e){return n.isValid(e)&&n._getFileState(e).proxy},getResumableFilesData:function(){var e=[];return n._iterateResumeRecords(function(t,i){n.moveInProgressToRemaining(null,i.chunking.inProgress,i.chunking.remaining);var r={name:i.name,remaining:i.chunking.remaining,size:i.size,uuid:i.uuid};i.key&&(r.key=i.key),e.push(r)}),e},isResumable:function(e){return!!o&&n.isValid(e)&&!n._getFileState(e).notResumable},moveInProgressToRemaining:function(e,t,i){var r=t||n._getFileState(e).chunking.inProgress,o=i||n._getFileState(e).chunking.remaining;r&&(g(qq.format("Moving these chunks from in-progress {}, to remaining.",JSON.stringify(r))),r.reverse(),qq.each(r,function(e,t){o.unshift(t)}),r.length=0)},pause:function(e){if(n.isValid(e))return g(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.",e,c(e))),n._getFileState(e).paused=!0,t(e),!0},reevaluateChunking:function(e){if(o&&n.isValid(e)){var t,i,r=n._getFileState(e);if(delete r.chunking,r.chunking={},t=n._getTotalChunks(e),t>1||o.mandatory){for(r.chunking.enabled=!0,r.chunking.parts=t,r.chunking.remaining=[],i=0;i=r?r:s+i,c=n._getTotalChunks(e),d=this._getFileState(e).temp.cachedChunks,p=d[t]||qq.sliceBlob(a,s,u);return d[t]=p,{part:t,start:s,end:u,count:c,blob:p,size:u-s}},_getChunkDataForCallback:function(e){return{partIndex:e.part,startByte:e.start+1,endByte:e.end,totalParts:e.count}},_getLocalStorageId:function(e){var t="5.0",n=c(e),r=l(e),a=o.partSize,s=p(e);return qq.format("qq{}resume{}-{}-{}-{}-{}",i,t,n,r,a,s)},_getMimeType:function(e){return n.getFile(e).type},_getPersistableData:function(e){return n._getFileState(e).chunking},_getTotalChunks:function(e){if(o){var t=l(e),n=o.partSize;return Math.ceil(t/n)}},_getXhr:function(e,t){var i=null==t?-1:t;return n._getFileState(e).temp.xhrs[i]},_getXhrs:function(e){return n._getFileState(e).temp.xhrs},_iterateResumeRecords:function(e){u&&qq.each(localStorage,function(t,n){if(0===t.indexOf(qq.format("qq{}resume",i))){var r=JSON.parse(n);e(t,r)}})},_initTempState:function(e){n._getFileState(e).temp={ajaxRequesters:{},chunkProgress:{},xhrs:{},cachedChunks:{}}},_markNotResumable:function(e){n._getFileState(e).notResumable=!0},_maybeDeletePersistedChunkData:function(e){var t;return!!(u&&n.isResumable(e)&&(t=n._getLocalStorageId(e),t&&localStorage.getItem(t)))&&(localStorage.removeItem(t),!0)},_maybePrepareForResume:function(e){var t,i,r=n._getFileState(e);u&&void 0===r.key&&(t=n._getLocalStorageId(e),i=localStorage.getItem(t),i&&(i=JSON.parse(i),q(i.uuid)?n._markNotResumable(e):(g(qq.format("Identified file with ID {} and name of {} as resumable.",e,c(e))),f(e,i.uuid),r.key=i.key,r.chunking=i.chunking,r.loaded=i.loaded,r.attemptingResume=!0,n.moveInProgressToRemaining(e))))},_maybePersistChunkedState:function(e){var t,i,r=n._getFileState(e);if(u&&n.isResumable(e)){t=n._getLocalStorageId(e),i={name:c(e),size:l(e),uuid:d(e),key:r.key,chunking:r.chunking,loaded:r.loaded,lastUpdated:Date.now()};try{localStorage.setItem(t,JSON.stringify(i))}catch(t){g(qq.format("Unable to save resume data for '{}' due to error: '{}'.",e,t.toString()),"warn")}}},_registerProgressHandler:function(e,t,i){var r=n._getXhr(e,t),o=c(e),a={simple:function(t,n){var i=l(e);t===n?h(e,o,i,i):h(e,o,t>=i?i-1:t,i)},chunked:function(r,a){var s=n._getFileState(e).temp.chunkProgress,u=n._getFileState(e).loaded,c=r,d=a,p=l(e),q=c-(d-i),f=u;s[t]=q,qq.each(s,function(e,t){f+=t}),h(e,o,f,p)}};r.upload.onprogress=function(e){if(e.lengthComputable){var t=null==i?"simple":"chunked";a[t](e.loaded,e.total)}}},_registerXhr:function(e,t,i,r){var o=null==t?-1:t,a=n._getFileState(e).temp;return a.xhrs=a.xhrs||{},a.ajaxRequesters=a.ajaxRequesters||{},a.xhrs[o]=i,r&&(a.ajaxRequesters[o]=r),i},_removeExpiredChunkingRecords:function(){var e=a.recordsExpireIn;n._iterateResumeRecords(function(t,n){var i=new Date(n.lastUpdated);i.setDate(i.getDate()+e),i.getTime()<=Date.now()&&(g("Removing expired resume record with key "+t),localStorage.removeItem(t))})},_shouldChunkThisFile:function(e){var t=n._getFileState(e);return t.chunking||n.reevaluateChunking(e),t.chunking.enabled}})},qq.DeleteFileAjaxRequester=function(e){"use strict";function t(){return"POST"===i.method.toUpperCase()?{_method:"DELETE"}:{}}var n,i={method:"DELETE",uuidParamName:"qquuid",endpointStore:{},maxConnections:3,customHeaders:function(e){return{}},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onDelete:function(e){},onDeleteComplete:function(e,t,n){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["POST","DELETE"],method:i.method,endpointStore:i.endpointStore,paramsStore:i.paramsStore,mandatedParams:t(),maxConnections:i.maxConnections,customHeaders:function(e){return i.customHeaders.get(e)},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete,cors:i.cors})),qq.extend(this,{sendDelete:function(e,t,r){var o=r||{};i.log("Submitting delete file request for "+e),"DELETE"===i.method?n.initTransport(e).withPath(t).withParams(o).send():(o[i.uuidParamName]=t,n.initTransport(e).withParams(o).send())}})},function(){function e(e){var t,n=e.naturalWidth,i=e.naturalHeight,r=document.createElement("canvas");return n*i>1048576&&(r.width=r.height=1,t=r.getContext("2d"),t.drawImage(e,-n+1,0),0===t.getImageData(0,0,1,1).data[3])}function t(e,t,n){var i,r,o,a,s=document.createElement("canvas"),u=0,c=n,l=n;for(s.width=1,s.height=n,i=s.getContext("2d"),i.drawImage(e,0,0),r=i.getImageData(0,0,1,n).data;l>u;)o=r[4*(l-1)+3],0===o?c=l:u=l,l=c+u>>1;return a=l/n,0===a?1:a}function n(e,t,n,i){var o=document.createElement("canvas"),a=n.mime||"image/jpeg",s=new qq.Promise;return r(e,t,o,n,i).then(function(){s.success(o.toDataURL(a,n.quality||.8))}),s}function i(e){var t=5241e3;if(!qq.ios())throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");if(e.origHeight*e.origWidth>t)return{newHeight:Math.round(Math.sqrt(t*(e.origHeight/e.origWidth))),newWidth:Math.round(Math.sqrt(t*(e.origWidth/e.origHeight)))}}function r(n,r,s,u,c){var l,d=n.naturalWidth,p=n.naturalHeight,q=u.width,f=u.height,h=s.getContext("2d"),g=new qq.Promise;return h.save(),u.resize?o({blob:r,canvas:s,image:n,imageHeight:p,imageWidth:d,orientation:u.orientation,resize:u.resize,targetHeight:f,targetWidth:q}):(qq.supportedFeatures.unlimitedScaledImageSize||(l=i({origWidth:q,origHeight:f}),l&&(qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h",q,f,l.newWidth,l.newHeight),"warn"),q=l.newWidth,f=l.newHeight)),a(s,q,f,u.orientation),qq.ios()?!function(){e(n)&&(d/=2,p/=2);var i,r,o,a=1024,s=document.createElement("canvas"),u=c?t(n,d,p):1,l=Math.ceil(a*q/d),g=Math.ceil(a*f/p/u),m=0,_=0;for(s.width=s.height=a,i=s.getContext("2d");ml&&(u=l,c=s*u/a<<0),d&&c>d&&(c=d,u=a*c/s<<0),i={width:u,height:c},qq.each(t,function(e,t){i[e]=t}),"img"===q?!function(){var t=e.src;n(o.srcImage,o.blob,i,p).then(function(n){e.src=n,t===e.src&&e.onload()})}():"canvas"===q&&r(this.srcImage,this.blob,e,i,p),void("function"==typeof this.onrender&&this.onrender(e)))},qq.MegaPixImage=s}(),qq.ImageGenerator=function(e){"use strict";function t(e){return"img"===e.tagName.toLowerCase()}function n(e){return"canvas"===e.tagName.toLowerCase()}function i(){return void 0!==(new Image).crossOrigin}function r(){var e=document.createElement("canvas");return e.getContext&&e.getContext("2d")}function o(e){var t=e.split("/"),n=t[t.length-1].split("?")[0],i=qq.getExtension(n);switch(i=i&&i.toLowerCase()){case"jpeg":case"jpg":return"image/jpeg";case"png":return"image/png";case"bmp":return"image/bmp";case"gif":return"image/gif";case"tiff":case"tif":return"image/tiff"}}function a(e){var t,n,i,r=document.createElement("a");return r.href=e,t=r.protocol,i=r.port,n=r.hostname,t.toLowerCase()!==window.location.protocol.toLowerCase()||(n.toLowerCase()!==window.location.hostname.toLowerCase()||i!==window.location.port&&!qq.ie())}function s(t,n){t.onload=function(){t.onload=null,t.onerror=null,n.success(t)},t.onerror=function(){t.onload=null,t.onerror=null,e("Problem drawing thumbnail!","error"),n.failure(t,"Problem drawing thumbnail!")}}function u(e,t){e.qqImageRendered=function(){t.success(e)}}function c(i,r){var o=t(i)||n(i);return t(i)?s(i,r):n(i)?u(i,r):(r.failure(i),e(qq.format("Element container of type {} is not supported!",i.tagName),"error")),o}function l(t,n,i){var r=new qq.Promise,o=new qq.Identify(t,e),a=i.maxSize,s=null==i.orient||i.orient,u=function(){n.onerror=null,n.onload=null,e("Could not render preview, file may be too large!","error"),r.failure(n,"Browser cannot render image!")};return o.isPreviewable().then(function(o){var l={parse:function(){return(new qq.Promise).success()}},d=s?new qq.Exif(t,e):l,p=new qq.MegaPixImage(t,u);c(n,r)&&d.parse().then(function(e){var t=e&&e.Orientation;p.render(n,{maxWidth:a,maxHeight:a,orientation:t,mime:o,resize:i.customResizeFunction})},function(t){e(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.",t)),p.render(n,{maxWidth:a,maxHeight:a,mime:o,resize:i.customResizeFunction})})},function(){e("Not previewable"),r.failure(n,"Not previewable")}),r}function d(e,t,n,i,r){var s=new Image,u=new qq.Promise;c(s,u),a(e)&&(s.crossOrigin="anonymous"),s.src=e,u.then(function(){c(t,n);var a=new qq.MegaPixImage(s);a.render(t,{maxWidth:i,maxHeight:i,mime:o(e),resize:r})},n.failure)}function p(e,t,n,i){c(t,n),qq(t).css({maxWidth:i+"px",maxHeight:i+"px"}),t.src=e}function q(e,o,s){var u=new qq.Promise,l=s.scale,q=l?s.maxSize:null;return l&&t(o)?r()?a(e)&&!i()?p(e,o,u,q):d(e,o,u,q):p(e,o,u,q):n(o)?d(e,o,u,q):c(o,u)&&(o.src=e),u}qq.extend(this,{generate:function(t,n,i){return qq.isString(t)?(e("Attempting to update thumbnail based on server response."),q(t,n,i||{})):(e("Attempting to draw client-side image preview."),l(t,n,i||{}))}}),this._testing={},this._testing.isImg=t,this._testing.isCanvas=n,this._testing.isCrossOrigin=a,this._testing.determineMimeOfFileName=o},qq.Exif=function(e,t){"use strict";function n(e){for(var t=0,n=0;e.length>0;)t+=parseInt(e.substring(0,2),16)*Math.pow(2,n),e=e.substring(2,e.length),n+=8;return t}function i(t,n){var r=t,o=n;return void 0===r&&(r=2,o=new qq.Promise),qq.readBlobToHex(e,r,4).then(function(e){var t,n=/^ffe([0-9])/.exec(e);n?"1"!==n[1]?(t=parseInt(e.slice(4,8),16),i(r+t+2,o)):o.success(r):o.failure("No EXIF header to be found!")}),o}function r(){var t=new qq.Promise;return qq.readBlobToHex(e,0,6).then(function(e){0!==e.indexOf("ffd8")?t.failure("Not a valid JPEG!"):i().then(function(e){t.success(e)},function(e){t.failure(e)})}),t}function o(t){var n=new qq.Promise;return qq.readBlobToHex(e,t+10,2).then(function(e){n.success("4949"===e)}),n}function a(t,i){var r=new qq.Promise;return qq.readBlobToHex(e,t+18,2).then(function(e){return i?r.success(n(e)):void r.success(parseInt(e,16))}),r}function s(t,n){var i=t+20,r=12*n;return qq.readBlobToHex(e,i,r)}function u(e){for(var t=[],n=0;n+24<=e.length;)t.push(e.slice(n,n+24)),n+=24;return t}function c(e,t){var i=16,r=qq.extend([],l),o={};return qq.each(t,function(t,a){var s,u,c,l=a.slice(0,4),p=e?n(l):parseInt(l,16),q=r.indexOf(p);if(q>=0&&(u=d[p].name,c=d[p].bytes,s=a.slice(i,i+2*c),o[u]=e?n(s):parseInt(s,16),r.splice(q,1)),0===r.length)return!1}),o}var l=[274],d={274:{name:"Orientation",bytes:2}};qq.extend(this,{parse:function(){var n=new qq.Promise,i=function(e){t(qq.format("EXIF header parse failed: '{}' ",e)),n.failure(e)};return r().then(function(r){t(qq.format("Moving forward with EXIF header parsing for '{}'",void 0===e.name?"blob":e.name)),o(r).then(function(e){t(qq.format("EXIF Byte order is {} endian",e?"little":"big")),a(r,e).then(function(o){t(qq.format("Found {} APP1 directory entries",o)),s(r,o).then(function(i){var r=u(i),o=c(e,r);t("Successfully parsed some EXIF tags"),n.success(o)},i)},i)},i)},i),n}}),this._testing={},this._testing.parseLittleEndian=n},qq.Identify=function(e,t){"use strict";function n(e,t){var n=!1,i=[].concat(e);return qq.each(i,function(e,i){if(0===t.indexOf(i))return n=!0,!1}),n}qq.extend(this,{isPreviewable:function(){var i=this,r=new qq.Promise,o=!1,a=void 0===e.name?"blob":e.name;return t(qq.format("Attempting to determine if {} can be rendered in this browser",a)),t("First pass: check type attribute of blob object."),this.isPreviewableSync()?(t("Second pass: check for magic bytes in file header."),qq.readBlobToHex(e,0,4).then(function(e){qq.each(i.PREVIEWABLE_MIME_TYPES,function(t,i){if(n(i,e))return("image/tiff"!==t||qq.supportedFeatures.tiffPreviews)&&(o=!0,r.success(t)),!1}),t(qq.format("'{}' is {} able to be rendered in this browser",a,o?"":"NOT")),o||r.failure()},function(){t("Error reading file w/ name '"+a+"'. Not able to be rendered in this browser."),r.failure()})):r.failure(),r},isPreviewableSync:function(){var n=e.type,i=qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES),n)>=0,r=!1,o=void 0===e.name?"blob":e.name;return i&&(r="image/tiff"!==n||qq.supportedFeatures.tiffPreviews),!r&&t(o+" is not previewable in this browser per the blob's type attr"),r}})},qq.Identify.prototype.PREVIEWABLE_MIME_TYPES={"image/jpeg":"ffd8ff","image/gif":"474946","image/png":"89504e","image/bmp":"424d","image/tiff":["49492a00","4d4d002a"]},qq.ImageValidation=function(e,t){"use strict";function n(e){var t=!1;return qq.each(e,function(e,n){if(n>0)return t=!0,!1}),t}function i(){var n=new qq.Promise;return new qq.Identify(e,t).isPreviewable().then(function(){var i=new Image,r=window.URL&&window.URL.createObjectURL?window.URL:window.webkitURL&&window.webkitURL.createObjectURL?window.webkitURL:null;r?(i.onerror=function(){t("Cannot determine dimensions for image. May be too large.","error"),n.failure()},i.onload=function(){n.success({width:this.width,height:this.height})},i.src=r.createObjectURL(e)):(t("No createObjectURL function available to generate image URL!","error"),n.failure())},n.failure),n}function r(e,t){var n;return qq.each(e,function(e,i){if(i>0){var r=/(max|min)(Width|Height)/.exec(e),o=r[2].charAt(0).toLowerCase()+r[2].slice(1),a=t[o];switch(r[1]){case"min":if(ai)return n=e,!1}}}),n}this.validate=function(e){var o=new qq.Promise;return t("Attempting to validate image."),n(e)?i().then(function(t){var n=r(e,t);n?o.failure(n):o.success()},o.success):o.success(),o}},qq.Session=function(e){"use strict";function t(e){return!!qq.isArray(e)||void i.log("Session response is not an array.","error")}function n(e,n,r,o){var a=!1;n=n&&t(e),n&&qq.each(e,function(e,t){if(null==t.uuid)a=!0,i.log(qq.format("Session response item {} did not include a valid UUID - ignoring.",e),"error");else if(null==t.name)a=!0,i.log(qq.format("Session response item {} did not include a valid name - ignoring.",e),"error");else try{return i.addFileRecord(t),!0}catch(e){a=!0,i.log(e.message,"error")}return!1}),o[n&&!a?"success":"failure"](e,r)}var i={endpoint:null,params:{},customHeaders:{},cors:{},addFileRecord:function(e){},log:function(e,t){}};qq.extend(i,e,!0),this.refresh=function(){var e=new qq.Promise,t=function(t,i,r){n(t,i,r,e)},r=qq.extend({},i),o=new qq.SessionAjaxRequester(qq.extend(r,{onComplete:t}));return o.queryServer(),e}},qq.SessionAjaxRequester=function(e){"use strict";function t(e,t,n){var r=null;if(null!=t.responseText)try{r=qq.parseJson(t.responseText)}catch(e){i.log("Problem parsing session response: "+e.message,"error"),n=!0}i.onComplete(r,!n,t)}var n,i={endpoint:null,customHeaders:{},params:{},cors:{expected:!1,sendCredentials:!1},onComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",endpointStore:{get:function(){return i.endpoint}},customHeaders:i.customHeaders,log:i.log,onComplete:t,cors:i.cors})),qq.extend(this,{queryServer:function(){var e=qq.extend({},i.params);i.log("Session query request."),n.initTransport("sessionRefresh").withParams(e).withCacheBuster().send()}})},qq.Scaler=function(e,t){"use strict";var n=e.customResizer,i=e.sendOriginal,r=e.orient,o=e.defaultType,a=e.defaultQuality/100,s=e.failureText,u=e.includeExif,c=this._getSortedSizes(e.sizes);qq.extend(this,{enabled:qq.supportedFeatures.scaling&&c.length>0,getFileRecords:function(e,l,d){var p=this,q=[],f=d.blob?d.blob:d,h=new qq.Identify(f,t);return h.isPreviewableSync()?(qq.each(c,function(e,i){var c=p._determineOutputType({defaultType:o,requestedType:i.type,refType:f.type});q.push({uuid:qq.getUniqueId(),name:p._getName(l,{name:i.name,type:c,refType:f.type}),blob:new qq.BlobProxy(f,qq.bind(p._generateScaledImage,p,{customResizeFunction:n,maxSize:i.maxSize,orient:r,type:c,quality:a,failedText:s,includeExif:u,log:t}))})}),q.push({uuid:e,name:l,size:f.size,blob:i?f:null})):q.push({uuid:e,name:l,size:f.size,blob:f}),q},handleNewFile:function(e,t,n,i,r,o,a,s){var u=this,c=(e.qqButtonId||e.blob&&e.blob.qqButtonId,[]),l=null,d=s.addFileToHandler,p=s.uploadData,q=s.paramsStore,f=qq.getUniqueId();qq.each(u.getFileRecords(n,t,e),function(e,t){var n,i=t.size;t.blob instanceof qq.BlobProxy&&(i=-1),n=p.addFile({uuid:t.uuid,name:t.name,size:i,batchId:o,proxyGroupId:f}),t.blob instanceof qq.BlobProxy?c.push(n):l=n,t.blob?(d(n,t.blob),r.push({id:n,file:t.blob})):p.setStatus(n,qq.status.REJECTED)}),null!==l&&(qq.each(c,function(e,t){var n={qqparentuuid:p.retrieve({id:l}).uuid,qqparentsize:p.retrieve({id:l}).size};n[a]=p.retrieve({id:t}).uuid,p.setParentId(t,l),q.addReadOnly(t,n)}),c.length&&!function(){var e={};e[a]=p.retrieve({id:l}).uuid,q.addReadOnly(l,e)}())}})},qq.extend(qq.Scaler.prototype,{scaleImage:function(e,t,n){"use strict";if(!qq.supportedFeatures.scaling)throw new qq.Error("Scaling is not supported in this browser!");var i=new qq.Promise,r=n.log,o=n.getFile(e),a=n.uploadData.retrieve({id:e}),s=a&&a.name,u=a&&a.uuid,c={customResizer:t.customResizer,sendOriginal:!1,orient:t.orient,defaultType:t.type||null,defaultQuality:t.quality,failedToScaleText:"Unable to scale",sizes:[{name:"",maxSize:t.maxSize}]},l=new qq.Scaler(c,r);return qq.Scaler&&qq.supportedFeatures.imagePreviews&&o?qq.bind(function(){var t=l.getFileRecords(u,s,o)[0];t&&t.blob instanceof qq.BlobProxy?t.blob.create().then(i.success,i.failure):(r(e+" is not a scalable image!","error"),i.failure())},this)():(i.failure(),r("Could not generate requested scaled image for "+e+". Scaling is either not possible in this browser, or the file could not be located.","error")),i},_determineOutputType:function(e){"use strict";var t=e.requestedType,n=e.defaultType,i=e.refType;return n||t?t&&qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES),t)>=0?"image/tiff"===t?qq.supportedFeatures.tiffPreviews?t:n:t:n:"image/jpeg"!==i?"image/png":i},_getName:function(e,t){"use strict";var n=e.lastIndexOf("."),i=t.type||"image/png",r=t.refType,o="",a=qq.getExtension(e),s="";return t.name&&t.name.trim().length&&(s=" ("+t.name+")"),n>=0?(o=e.substr(0,n),r!==i&&(a=i.split("/")[1]),o+=s+"."+a):o=e+s,o},_getSortedSizes:function(e){"use strict";return e=qq.extend([],e),e.sort(function(e,t){return e.maxSize>t.maxSize?1:e.maxSize=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),n=e.split(",")[0].split(":")[1].split(";")[0],i=new ArrayBuffer(t.length),r=new Uint8Array(i),qq.each(t,function(e,t){r[e]=t.charCodeAt(0)}),this._createBlob(i,n)},_createBlob:function(e,t){"use strict";var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})}}),qq.ExifRestorer=function(){var e={};return e.KEY_STR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e.encode64=function(e){var t,n,i,r,o,a="",s="",u="",c=0;do t=e[c++],n=e[c++],s=e[c++],i=t>>2,r=(3&t)<<4|n>>4,o=(15&n)<<2|s>>6,u=63&s,isNaN(n)?o=u=64:isNaN(s)&&(u=64),a=a+this.KEY_STR.charAt(i)+this.KEY_STR.charAt(r)+this.KEY_STR.charAt(o)+this.KEY_STR.charAt(u),t=n=s="",i=r=o=u="";while(ce.length)break}return n},e.decode64=function(e){var t,n,i,r,o,a="",s="",u=0,c=[],l=/[^A-Za-z0-9\+\/\=]/g;if(l.exec(e))throw new Error("There were invalid base64 characters in the input text. Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");do i=this.KEY_STR.indexOf(e.charAt(u++)),r=this.KEY_STR.indexOf(e.charAt(u++)),o=this.KEY_STR.indexOf(e.charAt(u++)),s=this.KEY_STR.indexOf(e.charAt(u++)),t=i<<2|r>>4,n=(15&r)<<4|o>>2,a=(3&o)<<6|s,c.push(t),64!=o&&c.push(n),64!=s&&c.push(a),t=n=a="",i=r=o=s="";while(u=0)return n=!1,!1}),n},c=function(e){p(e,-1,-1),delete n[e]},l=function(e,t,n){(0===t.length||u(t,n))&&(s(r,r),this.reset())},d=function(e){var i=t(e);i>0&&(p(e,0,i),n[e]={loaded:0,total:i})},p=function(e,t,o){var a=n[e]?n[e].loaded:0,u=n[e]?n[e].total:0;t===-1&&o===-1?(i-=a,r-=u):(t&&(i+=t-a),o&&(r+=o-u)),s(i,r)};qq.extend(this,{onAllComplete:l,onStatusChange:function(e,t,n){n===qq.status.CANCELED||n===qq.status.REJECTED?c(e):n===qq.status.SUBMITTING&&d(e)},onIndividualProgress:function(e,t,i){p(e,t,i),n[e]={loaded:t,total:i}},onNewSize:function(e){d(e)},reset:function(){n={},i=0,r=0}})},qq.PasteSupport=function(e){"use strict";function t(e){return e.type&&0===e.type.indexOf("image/")}function n(){o=qq(r.targetElement).attach("paste",function(e){var n=e.clipboardData;n&&qq.each(n.items,function(e,n){if(t(n)){var i=n.getAsFile();r.callbacks.pasteReceived(i)}})})}function i(){o&&o()}var r,o;r={targetElement:null,callbacks:{log:function(e,t){},pasteReceived:function(e){}}},qq.extend(r,e),n(),qq.extend(this,{reset:function(){i()}})},qq.FormSupport=function(e,t,n){"use strict";function i(e){e.getAttribute("action")&&(s.newEndpoint=e.getAttribute("action"))}function r(e,t){return!(e.checkValidity&&!e.checkValidity())||(n("Form did not pass validation checks - will not upload.","error"),void t())}function o(e){var n=e.submit;
+qq(e).attach("submit",function(i){i=i||window.event,i.preventDefault?i.preventDefault():i.returnValue=!1,r(e,n)&&t()}),e.submit=function(){r(e,n)&&t()}}function a(e){return e&&(qq.isString(e)&&(e=document.getElementById(e)),e&&(n("Attaching to form element."),i(e),u&&o(e))),e}var s=this,u=e.interceptSubmit,c=e.element,l=e.autoUpload;qq.extend(this,{newEndpoint:null,newAutoUpload:l,attachedToForm:!1,getFormInputsAsObject:function(){return null==c?null:s._form2Obj(c)}}),c=a(c),this.attachedToForm=!!c},qq.extend(qq.FormSupport.prototype,{_form2Obj:function(e){"use strict";var t={},n=function(e){var t=["button","image","reset","submit"];return qq.indexOf(t,e.toLowerCase())<0},i=function(e){return qq.indexOf(["checkbox","radio"],e.toLowerCase())>=0},r=function(e){return!(!i(e.type)||e.checked)||e.disabled&&"hidden"!==e.type.toLowerCase()},o=function(e){var t=null;return qq.each(qq(e).children(),function(e,n){if("option"===n.tagName.toLowerCase()&&n.selected)return t=n.value,!1}),t};return qq.each(e.elements,function(e,i){if(!qq.isInput(i,!0)&&"textarea"!==i.tagName.toLowerCase()||!n(i.type)||r(i)){if("select"===i.tagName.toLowerCase()&&!r(i)){var a=o(i);null!==a&&(t[i.name]=a)}}else t[i.name]=i.value}),t}}),qq.traditional=qq.traditional||{},qq.traditional.FormUploadHandler=function(e,t){"use strict";function n(e,t){var n,i,o;try{i=t.contentDocument||t.contentWindow.document,o=i.body.innerHTML,s("converting iframe's innerHTML to JSON"),s("innerHTML = "+o),o&&o.match(/^>>2]>>>24-o%4*8&255;t[i+o>>>2]|=a<<24-(i+o)%4*8}else if(n.length>65535)for(var o=0;o>>2]=n[o>>>2];else t.push.apply(t,n);return this.sigBytes+=r,this},clamp:function(){var t=this.words,n=this.sigBytes;t[n>>>2]&=4294967295<<32-n%4*8,t.length=e.ceil(n/4)},clone:function(){var e=r.clone.call(this);return e.words=this.words.slice(0),e},random:function(t){for(var n=[],i=0;i>>2]>>>24-r%4*8&255;i.push((o>>>4).toString(16)),i.push((15&o).toString(16))}return i.join("")},parse:function(e){for(var t=e.length,n=[],i=0;i>>3]|=parseInt(e.substr(i,2),16)<<24-i%8*4;return new o.init(n,t/2)}},u=a.Latin1={stringify:function(e){for(var t=e.words,n=e.sigBytes,i=[],r=0;r>>2]>>>24-r%4*8&255;i.push(String.fromCharCode(o))}return i.join("")},parse:function(e){for(var t=e.length,n=[],i=0;i>>2]|=(255&e.charCodeAt(i))<<24-i%4*8;return new o.init(n,t)}},c=a.Utf8={stringify:function(e){try{return decodeURIComponent(escape(u.stringify(e)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(e){return u.parse(unescape(encodeURIComponent(e)))}},l=i.BufferedBlockAlgorithm=r.extend({reset:function(){this._data=new o.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=c.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(t){var n=this._data,i=n.words,r=n.sigBytes,a=this.blockSize,s=4*a,u=r/s;u=t?e.ceil(u):e.max((0|u)-this._minBufferSize,0);var c=u*a,l=e.min(4*c,r);if(c){for(var d=0;d>>2]>>>24-o%4*8&255,s=t[o+1>>>2]>>>24-(o+1)%4*8&255,u=t[o+2>>>2]>>>24-(o+2)%4*8&255,c=a<<16|s<<8|u,l=0;l<4&&o+.75*l>>6*(3-l)&63));var d=i.charAt(64);if(d)for(;r.length%4;)r.push(d);return r.join("")},parse:function(e){var t=e.length,i=this._map,r=i.charAt(64);if(r){var o=e.indexOf(r);o!=-1&&(t=o)}for(var a=[],s=0,u=0;u>>6-u%4*2;a[s>>>2]|=(c|l)<<24-s%4*8,s++}return n.create(a,s)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}}(),function(){var e=qq.CryptoJS,t=e.lib,n=t.Base,i=e.enc,r=i.Utf8,o=e.algo;o.HMAC=n.extend({init:function(e,t){e=this._hasher=new e.init,"string"==typeof t&&(t=r.parse(t));var n=e.blockSize,i=4*n;t.sigBytes>i&&(t=e.finalize(t)),t.clamp();for(var o=this._oKey=t.clone(),a=this._iKey=t.clone(),s=o.words,u=a.words,c=0;c>>31}var d=(i<<5|i>>>27)+u+o[c];d+=c<20?(r&a|~r&s)+1518500249:c<40?(r^a^s)+1859775393:c<60?(r&a|r&s|a&s)-1894007588:(r^a^s)-899497514,u=s,s=a,a=r<<30|r>>>2,r=i,i=d}n[0]=n[0]+i|0,n[1]=n[1]+r|0,n[2]=n[2]+a|0,n[3]=n[3]+s|0,n[4]=n[4]+u|0},_doFinalize:function(){var e=this._data,t=e.words,n=8*this._nDataBytes,i=8*e.sigBytes;return t[i>>>5]|=128<<24-i%32,t[(i+64>>>9<<4)+14]=Math.floor(n/4294967296),t[(i+64>>>9<<4)+15]=n,e.sigBytes=4*t.length,this._process(),this._hash},clone:function(){var e=i.clone.call(this);return e._hash=this._hash.clone(),e}});e.SHA1=i._createHelper(a),e.HmacSHA1=i._createHmacHelper(a)}(),function(e){var t=qq.CryptoJS,n=t.lib,i=n.WordArray,r=n.Hasher,o=t.algo,a=[],s=[];!function(){function t(t){for(var n=e.sqrt(t),i=2;i<=n;i++)if(!(t%i))return!1;return!0}function n(e){return 4294967296*(e-(0|e))|0}for(var i=2,r=0;r<64;)t(i)&&(r<8&&(a[r]=n(e.pow(i,.5))),s[r]=n(e.pow(i,1/3)),r++),i++}();var u=[],c=o.SHA256=r.extend({_doReset:function(){this._hash=new i.init(a.slice(0))},_doProcessBlock:function(e,t){for(var n=this._hash.words,i=n[0],r=n[1],o=n[2],a=n[3],c=n[4],l=n[5],d=n[6],p=n[7],q=0;q<64;q++){if(q<16)u[q]=0|e[t+q];else{var f=u[q-15],h=(f<<25|f>>>7)^(f<<14|f>>>18)^f>>>3,g=u[q-2],m=(g<<15|g>>>17)^(g<<13|g>>>19)^g>>>10;u[q]=h+u[q-7]+m+u[q-16]}var _=c&l^~c&d,S=i&r^i&o^r&o,b=(i<<30|i>>>2)^(i<<19|i>>>13)^(i<<10|i>>>22),v=(c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25),y=p+v+_+s[q]+u[q],w=b+S;p=d,d=l,l=c,c=a+y|0,a=o,o=r,r=i,i=y+w|0}n[0]=n[0]+i|0,n[1]=n[1]+r|0,n[2]=n[2]+o|0,n[3]=n[3]+a|0,n[4]=n[4]+c|0,n[5]=n[5]+l|0,n[6]=n[6]+d|0,n[7]=n[7]+p|0},_doFinalize:function(){var t=this._data,n=t.words,i=8*this._nDataBytes,r=8*t.sigBytes;return n[r>>>5]|=128<<24-r%32,n[(r+64>>>9<<4)+14]=e.floor(i/4294967296),n[(r+64>>>9<<4)+15]=i,t.sigBytes=4*n.length,this._process(),this._hash},clone:function(){var e=r.clone.call(this);return e._hash=this._hash.clone(),e}});t.SHA256=r._createHelper(c),t.HmacSHA256=r._createHmacHelper(c)}(Math),function(){if("function"==typeof ArrayBuffer){var e=qq.CryptoJS,t=e.lib,n=t.WordArray,i=n.init,r=n.init=function(e){if(e instanceof ArrayBuffer&&(e=new Uint8Array(e)),(e instanceof Int8Array||e instanceof Uint8ClampedArray||e instanceof Int16Array||e instanceof Uint16Array||e instanceof Int32Array||e instanceof Uint32Array||e instanceof Float32Array||e instanceof Float64Array)&&(e=new Uint8Array(e.buffer,e.byteOffset,e.byteLength)),e instanceof Uint8Array){for(var t=e.byteLength,n=[],r=0;r>>2]|=e[r]<<24-r%4*8;i.call(this,n,t)}else i.apply(this,arguments)};r.prototype=n}}(),qq.s3=qq.s3||{},qq.s3.util=qq.s3.util||function(){"use strict";return{ALGORITHM_PARAM_NAME:"x-amz-algorithm",AWS_PARAM_PREFIX:"x-amz-meta-",CREDENTIAL_PARAM_NAME:"x-amz-credential",DATE_PARAM_NAME:"x-amz-date",REDUCED_REDUNDANCY_PARAM_NAME:"x-amz-storage-class",REDUCED_REDUNDANCY_PARAM_VALUE:"REDUCED_REDUNDANCY",SERVER_SIDE_ENCRYPTION_PARAM_NAME:"x-amz-server-side-encryption",SERVER_SIDE_ENCRYPTION_PARAM_VALUE:"AES256",SESSION_TOKEN_PARAM_NAME:"x-amz-security-token",V4_ALGORITHM_PARAM_VALUE:"AWS4-HMAC-SHA256",V4_SIGNATURE_PARAM_NAME:"x-amz-signature",CASE_SENSITIVE_PARAM_NAMES:["Cache-Control","Content-Disposition","Content-Encoding","Content-MD5"],UNSIGNABLE_REST_HEADER_NAMES:["Cache-Control","Content-Disposition","Content-Encoding","Content-MD5"],UNPREFIXED_PARAM_NAMES:["Cache-Control","Content-Disposition","Content-Encoding","Content-MD5","x-amz-server-side-encryption-customer-algorithm","x-amz-server-side-encryption-customer-key","x-amz-server-side-encryption-customer-key-MD5"],getBucket:function(e){var t,n=[/^(?:https?:\/\/)?([a-z0-9.\-_]+)\.s3(?:-[a-z0-9\-]+)?\.amazonaws\.com/i,/^(?:https?:\/\/)?s3(?:-[a-z0-9\-]+)?\.amazonaws\.com\/([a-z0-9.\-_]+)/i,/^(?:https?:\/\/)?([a-z0-9.\-_]+)/i];return qq.each(n,function(n,i){var r=i.exec(e);if(r)return t=r[1],!1}),t},_getPrefixedParamName:function(e){return qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES,e)>=0?e:qq.s3.util.AWS_PARAM_PREFIX+e},getPolicy:function(e){var t={},n=[],i=e.bucket,r=e.date,o=e.clockDrift,a=e.key,s=e.accessKey,u=e.acl,c=e.type,l=e.expectedStatus,d=e.sessionToken,p=e.params,q=qq.s3.util.getSuccessRedirectAbsoluteUrl(e.successRedirectUrl),f=e.minFileSize,h=e.maxFileSize,g=e.reducedRedundancy,m=e.region,_=e.serverSideEncryption,S=e.signatureVersion;return t.expiration=qq.s3.util.getPolicyExpirationDate(r,o),n.push({acl:u}),n.push({bucket:i}),c&&n.push({"Content-Type":c}),l&&n.push({success_action_status:l.toString()}),q&&n.push({success_action_redirect:q}),g&&(n.push({}),n[n.length-1][qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]=qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE),d&&(n.push({}),n[n.length-1][qq.s3.util.SESSION_TOKEN_PARAM_NAME]=d),_&&(n.push({}),n[n.length-1][qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]=qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE),2===S?n.push({key:a}):4===S&&(n.push({}),n[n.length-1][qq.s3.util.ALGORITHM_PARAM_NAME]=qq.s3.util.V4_ALGORITHM_PARAM_VALUE,n.push({}),n[n.length-1].key=a,n.push({}),n[n.length-1][qq.s3.util.CREDENTIAL_PARAM_NAME]=qq.s3.util.getV4CredentialsString({date:r,key:s,region:m}),n.push({}),n[n.length-1][qq.s3.util.DATE_PARAM_NAME]=qq.s3.util.getV4PolicyDate(r,o)),qq.each(p,function(e,t){var i=qq.s3.util._getPrefixedParamName(e),r={};qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES,i)>=0?r[i]=t:r[i]=encodeURIComponent(t),n.push(r)}),t.conditions=n,qq.s3.util.enforceSizeLimits(t,f,h),t},refreshPolicyCredentials:function(e,t){var n=!1;qq.each(e.conditions,function(e,i){qq.each(i,function(e,r){e===qq.s3.util.SESSION_TOKEN_PARAM_NAME&&(i[e]=t,n=!0)})}),n||(e.conditions.push({}),e.conditions[e.conditions.length-1][qq.s3.util.SESSION_TOKEN_PARAM_NAME]=t)},generateAwsParams:function(e,t){var n,i={},r=e.params,o=new qq.Promise,a=e.sessionToken,s=e.clockDrift,u=e.type,c=e.key,l=e.accessKey,d=e.acl,p=e.expectedStatus,q=qq.s3.util.getSuccessRedirectAbsoluteUrl(e.successRedirectUrl),f=e.reducedRedundancy,h=e.region,g=e.serverSideEncryption,m=e.signatureVersion,_=new Date,S=e.log;return e.date=_,n=qq.s3.util.getPolicy(e),i.key=c,u&&(i["Content-Type"]=u),p&&(i.success_action_status=p),q&&(i.success_action_redirect=q),f&&(i[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]=qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE),g&&(i[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]=qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE),a&&(i[qq.s3.util.SESSION_TOKEN_PARAM_NAME]=a),i.acl=d,qq.each(r,function(e,t){var n=qq.s3.util._getPrefixedParamName(e);qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES,n)>=0?i[n]=t:i[n]=encodeURIComponent(t)}),2===m?i.AWSAccessKeyId=l:4===m&&(i[qq.s3.util.ALGORITHM_PARAM_NAME]=qq.s3.util.V4_ALGORITHM_PARAM_VALUE,i[qq.s3.util.CREDENTIAL_PARAM_NAME]=qq.s3.util.getV4CredentialsString({date:_,key:l,region:h}),i[qq.s3.util.DATE_PARAM_NAME]=qq.s3.util.getV4PolicyDate(_,s)),t(n).then(function(t,n,r){i.policy=t.policy,2===e.signatureVersion?(i.signature=t.signature,n&&(i.AWSAccessKeyId=n)):4===e.signatureVersion&&(i[qq.s3.util.V4_SIGNATURE_PARAM_NAME]=t.signature),r&&(i[qq.s3.util.SESSION_TOKEN_PARAM_NAME]=r),o.success(i)},function(e){e=e||"Can't continue further with request to S3 as we did not receive a valid signature and policy from the server.",S("Policy signing failed. "+e,"error"),o.failure(e)}),o},enforceSizeLimits:function(e,t,n){var i=t<0?0:t,r=n<=0?9007199254740992:n;(t>0||n>0)&&e.conditions.push(["content-length-range",i.toString(),r.toString()])},getPolicyExpirationDate:function(e,t){var n=new Date(e.getTime()+t);return qq.s3.util.getPolicyDate(n,5)},getCredentialsDate:function(e){return e.getUTCFullYear()+""+("0"+(e.getUTCMonth()+1)).slice(-2)+("0"+e.getUTCDate()).slice(-2)},getPolicyDate:function(e,t){var n,i,r=t||0;return e.setMinutes(e.getMinutes()+(r||0)),Date.prototype.toISOString?e.toISOString():(n=function(e){return i=String(e),1===i.length&&(i="0"+i),i},e.getUTCFullYear()+"-"+n(e.getUTCMonth()+1)+"-"+n(e.getUTCDate())+"T"+n(e.getUTCHours())+":"+n(e.getUTCMinutes())+":"+n(e.getUTCSeconds())+"."+String((e.getUTCMilliseconds()/1e3).toFixed(3)).slice(2,5)+"Z")},parseIframeResponse:function(e){var t=e.contentDocument||e.contentWindow.document,n=t.location.search,i=/bucket=(.+)&key=(.+)&etag=(.+)/.exec(n);if(i)return{bucket:i[1],key:i[2],etag:i[3].replace(/%22/g,"")}},getSuccessRedirectAbsoluteUrl:function(e){if(e){var t,n=document.createElement("div");return qq.ie7()?(n.innerHTML=" ",t=n.firstChild,t.href):(t=document.createElement("a"),t.href=e,t.href=t.href,t.href)}},getV4CredentialsString:function(e){return e.key+"/"+qq.s3.util.getCredentialsDate(e.date)+"/"+e.region+"/s3/aws4_request"},getV4PolicyDate:function(e,t){var n=new Date(e.getTime()+t);return qq.s3.util.getCredentialsDate(n)+"T"+("0"+n.getUTCHours()).slice(-2)+("0"+n.getUTCMinutes()).slice(-2)+("0"+n.getUTCSeconds()).slice(-2)+"Z"},encodeQueryStringParam:function(e){var t=encodeURIComponent(e);return t=t.replace(/[!'()]/g,escape),t=t.replace(/\*/g,"%2A"),t.replace(/%20/g,"+")},uriEscape:function(e){var t=encodeURIComponent(e);return t=t.replace(/[^A-Za-z0-9_.~\-%]+/g,escape),t=t.replace(/[*]/g,function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})},uriEscapePath:function(e){var t=[];return qq.each(e.split("/"),function(e,n){t.push(qq.s3.util.uriEscape(n))}),t.join("/")}}}(),function(){"use strict";qq.nonTraditionalBasePublicApi={setUploadSuccessParams:function(e,t){this._uploadSuccessParamsStore.set(e,t)},setUploadSuccessEndpoint:function(e,t){this._uploadSuccessEndpointStore.set(e,t)}},qq.nonTraditionalBasePrivateApi={_onComplete:function(e,t,n,i){var r,o,a=!!n.success,s=this,u=arguments,c=this._uploadSuccessEndpointStore.get(e),l=this._options.uploadSuccess.customHeaders,d=this._options.uploadSuccess.method,p=this._options.cors,q=new qq.Promise,f=this._uploadSuccessParamsStore.get(e),h=this._paramsStore.get(e),g=function(t){delete s._failedSuccessRequestCallbacks[e],qq.extend(n,t),qq.FineUploaderBasic.prototype._onComplete.apply(s,u),q.success(t)},m=function(o){var a=r;qq.extend(n,o),n&&n.reset&&(a=null),a?s._failedSuccessRequestCallbacks[e]=a:delete s._failedSuccessRequestCallbacks[e],s._onAutoRetry(e,t,n,i,a)||(qq.FineUploaderBasic.prototype._onComplete.apply(s,u),q.failure(o))};return a&&c?(o=new qq.UploadSuccessAjaxRequester({endpoint:c,method:d,customHeaders:l,cors:p,log:qq.bind(this.log,this)}),qq.extend(f,s._getEndpointSpecificParams(e,n,i),!0),h&&qq.extend(f,h,!0),r=qq.bind(function(){o.sendSuccessRequest(e,f).then(g,m)},s),r(),q):qq.FineUploaderBasic.prototype._onComplete.apply(this,arguments)},_manualRetry:function(e){var t=this._failedSuccessRequestCallbacks[e];return qq.FineUploaderBasic.prototype._manualRetry.call(this,e,t)}}}(),function(){"use strict";qq.s3.FineUploaderBasic=function(e){var t={request:{accessKey:null,clockDrift:0},objectProperties:{acl:"private",bucket:qq.bind(function(e){return qq.s3.util.getBucket(this.getEndpoint(e))},this),host:qq.bind(function(e){return/(?:http|https):\/\/(.+)(?:\/.+)?/.exec(this._endpointStore.get(e))[1]},this),key:"uuid",reducedRedundancy:!1,region:"us-east-1",serverSideEncryption:!1},credentials:{accessKey:null,secretKey:null,expiration:null,sessionToken:null},signature:{customHeaders:{},endpoint:null,version:2},uploadSuccess:{endpoint:null,method:"POST",params:{},customHeaders:{}},iframeSupport:{localBlankPagePath:null},chunking:{partSize:5242880},cors:{allowXdr:!0},callbacks:{onCredentialsExpired:function(){}}};qq.extend(t,e,!0),this.setCredentials(t.credentials,!0)||(this._currentCredentials.accessKey=t.request.accessKey),this._aclStore=this._createStore(t.objectProperties.acl),qq.FineUploaderBasic.call(this,t),this._uploadSuccessParamsStore=this._createStore(this._options.uploadSuccess.params),this._uploadSuccessEndpointStore=this._createStore(this._options.uploadSuccess.endpoint),this._failedSuccessRequestCallbacks={},this._cannedKeys={},this._cannedBuckets={},this._buckets={},this._hosts={}},qq.extend(qq.s3.FineUploaderBasic.prototype,qq.basePublicApi),qq.extend(qq.s3.FineUploaderBasic.prototype,qq.basePrivateApi),qq.extend(qq.s3.FineUploaderBasic.prototype,qq.nonTraditionalBasePublicApi),qq.extend(qq.s3.FineUploaderBasic.prototype,qq.nonTraditionalBasePrivateApi),qq.extend(qq.s3.FineUploaderBasic.prototype,{getBucket:function(e){return null==this._cannedBuckets[e]?this._buckets[e]:this._cannedBuckets[e]},getKey:function(e){return null==this._cannedKeys[e]?this._handler.getThirdPartyFileId(e):this._cannedKeys[e]},reset:function(){qq.FineUploaderBasic.prototype.reset.call(this),this._failedSuccessRequestCallbacks=[],this._buckets={},this._hosts={}},setCredentials:function(e,t){if(e&&e.secretKey){if(!e.accessKey)throw new qq.Error("Invalid credentials: no accessKey");if(!e.expiration)throw new qq.Error("Invalid credentials: no expiration");return this._currentCredentials=qq.extend({},e),qq.isString(e.expiration)&&(this._currentCredentials.expiration=new Date(e.expiration)),!0}if(!t)throw new qq.Error("Invalid credentials parameter!");this._currentCredentials={}},setAcl:function(e,t){this._aclStore.set(e,t)},_createUploadHandler:function(){var e=this,t={aclStore:this._aclStore,getBucket:qq.bind(this._determineBucket,this),getHost:qq.bind(this._determineHost,this),getKeyName:qq.bind(this._determineKeyName,this),iframeSupport:this._options.iframeSupport,objectProperties:this._options.objectProperties,signature:this._options.signature,clockDrift:this._options.request.clockDrift,validation:{minSizeLimit:this._options.validation.minSizeLimit,maxSizeLimit:this._options.validation.sizeLimit}};return qq.override(this._endpointStore,function(e){return{get:function(t){var n=e.get(t);return n.indexOf("http")<0?"http://"+n:n}}}),qq.override(this._paramsStore,function(e){return{get:function(t){var n=e.get(t),i={};return qq.each(n,function(e,t){var n=e;qq.indexOf(qq.s3.util.CASE_SENSITIVE_PARAM_NAMES,n)<0&&(n=n.toLowerCase()),i[n]=qq.isFunction(t)?t():t}),i}}}),t.signature.credentialsProvider={get:function(){return e._currentCredentials},onExpired:function(){var t=new qq.Promise,n=e._options.callbacks.onCredentialsExpired();return qq.isGenericPromise(n)?n.then(function(n){try{e.setCredentials(n),t.success()}catch(n){e.log("Invalid credentials returned from onCredentialsExpired callback! ("+n.message+")","error"),t.failure("onCredentialsExpired did not return valid credentials.")}},function(n){e.log("onCredentialsExpired callback indicated failure! ("+n+")","error"),t.failure("onCredentialsExpired callback failed.")}):(e.log("onCredentialsExpired callback did not return a promise!","error"),t.failure("Unexpected return value for onCredentialsExpired.")),t}},qq.FineUploaderBasic.prototype._createUploadHandler.call(this,t,"s3")},_determineObjectPropertyValue:function(e,t){var n=this._options.objectProperties[t],i=new qq.Promise,r=this;return qq.isFunction(n)?(n=n(e),qq.isGenericPromise(n)?i=n:i.success(n)):qq.isString(n)&&i.success(n),i.then(function(n){r["_"+t+"s"][e]=n},function(n){qq.log("Problem determining "+t+" for ID "+e+" ("+n+")","error")}),i},_determineBucket:function(e){return this._determineObjectPropertyValue(e,"bucket")},_determineHost:function(e){return this._determineObjectPropertyValue(e,"host")},_determineKeyName:function(e,t){var n=new qq.Promise,i=this._options.objectProperties.key,r=qq.getExtension(t),o=n.failure,a=function(e,t){var i=e;void 0!==t&&(i+="."+t),n.success(i)};switch(i){case"uuid":a(this.getUuid(e),r);break;case"filename":a(t);break;default:qq.isFunction(i)?this._handleKeynameFunction(i,e,a,o):(this.log(i+" is not a valid value for the s3.keyname option!","error"),o())}return n},_handleKeynameFunction:function(e,t,n,i){var r=this,o=function(e){n(e)},a=function(e){r.log(qq.format("Failed to retrieve key name for {}. Reason: {}",t,e||"null"),"error"),i(e)},s=e.call(this,t);qq.isGenericPromise(s)?s.then(o,a):null==s?a():o(s)},_getEndpointSpecificParams:function(e,t,n){var i={key:this.getKey(e),uuid:this.getUuid(e),name:this.getName(e),bucket:this.getBucket(e)};return n&&n.getResponseHeader("ETag")?i.etag=n.getResponseHeader("ETag"):t.etag&&(i.etag=t.etag),i},_onSubmitDelete:function(e,t){var n={key:this.getKey(e),bucket:this.getBucket(e)};return qq.FineUploaderBasic.prototype._onSubmitDelete.call(this,e,t,n)},_addCannedFile:function(e){var t;if(null==e.s3Key)throw new qq.Error("Did not find s3Key property in server session response. This is required!");return t=qq.FineUploaderBasic.prototype._addCannedFile.apply(this,arguments),this._cannedKeys[t]=e.s3Key,this._cannedBuckets[t]=e.s3Bucket,t}})}(),window.Uint8ClampedArray||(window.Uint8ClampedArray=function(){}),qq.s3.RequestSigner=function(e){"use strict";function t(e,t,n){var i,r,o=t.responseText,a=c[e],s=a.promise,u=a.signatureConstructor;if(delete c[e],o)try{r=qq.parseJson(o)}catch(e){l.log("Error attempting to parse signature response: "+e,"error")}r&&r.error?(n=!0,i=r.error):r&&r.invalid?(n=!0,i="Invalid policy document or request headers!"):r?l.expectingPolicy&&!r.policy?(n=!0,i="Response does not include the base64 encoded policy!"):r.signature||(n=!0,i="Response does not include the signature!"):(n=!0,i="Received an empty or invalid response from the server!"),n?(i&&l.log(i,"error"),s.failure(i)):u?d(u,r.signature,s):s.success(r)}function n(e,t,n){var i,r,o,a=new qq.Promise,s="POST",c=[],d="",f=new Date,h=function(e){var n,a=[];return qq.each(e.headers,function(e){c.push(e)}),c.sort(),qq.each(c,function(t,i){qq.indexOf(qq.s3.util.UNSIGNABLE_REST_HEADER_NAMES,i)<0?d+=i.toLowerCase()+":"+e.headers[i].trim()+"\n":"Content-MD5"===i?n=e.headers[i]:a.unshift(t)}),qq.each(a,function(e,t){c.splice(t,1)}),r={bucket:e.bucket,contentMd5:n,contentType:e.contentType,date:f,drift:l.signatureSpec.drift,endOfUrl:i,hashedContent:e.hashedContent,headerNames:c,headersStr:d,method:s},o=2===t?p.getStringToSign(r):q.getStringToSign(r),{date:f,endOfUrl:i,signedHeaders:4===t?q.getSignedHeaders(r.headerNames):null,toSign:4===t?o.hashed:o,toSignRaw:4===t?o.raw:o}};switch(n.type){case u.REQUEST_TYPE.MULTIPART_ABORT:s="DELETE",i=qq.format("uploadId={}",n.uploadId);break;case u.REQUEST_TYPE.MULTIPART_INITIATE:i="uploads";break;case u.REQUEST_TYPE.MULTIPART_COMPLETE:i=qq.format("uploadId={}",n.uploadId);break;case u.REQUEST_TYPE.MULTIPART_UPLOAD:s="PUT",i=qq.format("partNumber={}&uploadId={}",n.partNum,n.uploadId)}return i=n.key+"?"+i,4===t?q.getEncodedHashedPayload(n.content).then(function(e){n.headers["x-amz-content-sha256"]=e,n.headers.Host=n.host,n.headers["x-amz-date"]=qq.s3.util.getV4PolicyDate(f,l.signatureSpec.drift),n.hashedContent=e,a.success(h(n))},function(e){a.failure(e)}):a.success(h(n)),a}function i(e,t,n,i,a){var s;t.signatureConstructor?(a&&(s=t.signatureConstructor.getHeaders(),s[qq.s3.util.SESSION_TOKEN_PARAM_NAME]=a,t.signatureConstructor.withHeaders(s)),t.signatureConstructor.getToSign(e).then(function(e){o(t.signatureConstructor,e.stringToSign,n)},function(e){n.failure(e)})):(a&&qq.s3.util.refreshPolicyCredentials(t,a),r(t,n,i,a))}function r(e,t,n,i){4===l.signatureSpec.version?q.signPolicy(e,t,n,i):p.signPolicy(e,t,n,i)}function o(e,t,n){4===l.signatureSpec.version?q.signApiRequest(e,t,n):p.signApiRequest(e,t,n)}var a,s,u=this,c={},l={expectingPolicy:!1,method:"POST",signatureSpec:{drift:0,credentialsProvider:{},endpoint:null,customHeaders:{},version:2},maxConnections:3,endpointStore:{},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){}},d=function(e,t,n){var i=e.getHeaders();4===l.signatureSpec.version?i.Authorization=qq.s3.util.V4_ALGORITHM_PARAM_VALUE+" Credential="+l.signatureSpec.credentialsProvider.get().accessKey+"/"+qq.s3.util.getCredentialsDate(e.getRequestDate())+"/"+l.signatureSpec.region+"/s3/aws4_request,SignedHeaders="+e.getSignedHeaders()+",Signature="+t:i.Authorization="AWS "+l.signatureSpec.credentialsProvider.get().accessKey+":"+t,n.success(i,e.getEndOfUrl())},p={getStringToSign:function(e){return qq.format("{}\n{}\n{}\n\n{}/{}/{}",e.method,e.contentMd5||"",e.contentType||"",e.headersStr||"\n",e.bucket,e.endOfUrl)},signApiRequest:function(e,t,n){var i=qq.CryptoJS.enc.Utf8.parse(t),r=qq.CryptoJS.HmacSHA1(i,s.get().secretKey),o=qq.CryptoJS.enc.Base64.stringify(r);d(e,o,n)},signPolicy:function(e,t,n,i){var r=JSON.stringify(e),o=qq.CryptoJS.enc.Utf8.parse(r),a=qq.CryptoJS.enc.Base64.stringify(o),u=qq.CryptoJS.HmacSHA1(a,s.get().secretKey),c=qq.CryptoJS.enc.Base64.stringify(u);t.success({policy:a,signature:c},n,i)}},q={getCanonicalQueryString:function(e){var t,n,i,r=e.indexOf("?"),o="";return r>=0&&(t={},i=e.substr(r+1).split("&"),qq.each(i,function(e,n){var i=n.split("="),r=i[1];null==r&&(r=""),t[encodeURIComponent(i[0])]=encodeURIComponent(r)}),n=Object.keys(t).sort(),n.forEach(function(e,i){o+=e+"="+t[e],i0&&(t=e.substr(0,n)),"/"+t},getEncodedHashedPayload:function(e){var t,n=new qq.Promise;return qq.isBlob(e)?(t=new FileReader,t.onloadend=function(e){if(e.target.readyState===FileReader.DONE)if(e.target.error)n.failure(e.target.error);else{var t=qq.CryptoJS.lib.WordArray.create(e.target.result);n.success(qq.CryptoJS.SHA256(t).toString())}},t.readAsArrayBuffer(e)):(e=e||"",n.success(qq.CryptoJS.SHA256(e).toString())),n},getScope:function(e,t){return qq.s3.util.getCredentialsDate(e)+"/"+t+"/s3/aws4_request"},getStringToSign:function(e){var t=q.getCanonicalRequest(e),n=qq.s3.util.getV4PolicyDate(e.date,e.drift),i=qq.CryptoJS.SHA256(t).toString(),r=q.getScope(e.date,l.signatureSpec.region),o="AWS4-HMAC-SHA256\n{}\n{}\n{}";return{hashed:qq.format(o,n,r,i),raw:qq.format(o,n,r,t)}},getSignedHeaders:function(e){var t="";return e.forEach(function(n,i){t+=n.toLowerCase(),iDate.now()?i(e,t,u):s.onExpired().then(function(){i(e,t,u,s.get().accessKey,s.get().sessionToken)},function(e){l.log("Attempt to update expired credentials apparently failed! Unable to sign request. ","error"),u.failure("Unable to sign request - expired credentials.")}):(l.log("Submitting S3 signature request for "+e),o?o.getToSign(e).then(function(t){r={headers:t.stringToSignRaw},a.initTransport(e).withParams(r).withQueryParams(n).send()},function(e){l.log("Failed to construct signature. ","error"),u.failure("Failed to construct signature.")}):a.initTransport(e).withParams(r).withQueryParams(n).send(),c[e]={promise:u,signatureConstructor:o}),u},constructStringToSign:function(e,t,i,r){var o,a,u,c,d,p={};return{withHeaders:function(e){return p=e,this},withUploadId:function(e){return o=e,this},withContent:function(e){return a=e,this},withContentType:function(e){return u=e,this},withPartNum:function(e){return c=e,this},getToSign:function(q){var f=s.get().sessionToken,h=new qq.Promise,g=new Date(Date.now()+l.signatureSpec.drift);return p["x-amz-date"]=g.toUTCString(),f&&(p[qq.s3.util.SESSION_TOKEN_PARAM_NAME]=f),n(q,l.signatureSpec.version,{bucket:t,content:a,contentType:u,headers:p,host:i,key:r,partNum:c,type:e,uploadId:o}).then(function(e){d=e,h.success({headers:function(){return u&&(p["Content-Type"]=u),delete p.Host,p}(),date:d.date,endOfUrl:d.endOfUrl,signedHeaders:d.signedHeaders,stringToSign:d.toSign,stringToSignRaw:d.toSignRaw})},function(e){h.failure(e)}),h},getHeaders:function(){return qq.extend({},p)},getEndOfUrl:function(){return d&&d.endOfUrl},getRequestDate:function(){return d&&d.date},getSignedHeaders:function(){return d&&d.signedHeaders}}}})},qq.s3.RequestSigner.prototype.REQUEST_TYPE={MULTIPART_INITIATE:"multipart_initiate",MULTIPART_COMPLETE:"multipart_complete",MULTIPART_ABORT:"multipart_abort",MULTIPART_UPLOAD:"multipart_upload"},qq.UploadSuccessAjaxRequester=function(e){"use strict";function t(e,t,n){var o,a=i[e],s=t.responseText,u={success:!0},c={success:!1};delete i[e],r.log(qq.format("Received the following response body to an upload success request for id {}: {}",e,s));try{o=qq.parseJson(s),n||o&&(o.error||o.success===!1)?(r.log("Upload success request was rejected by the server.","error"),a.failure(qq.extend(o,c))):(r.log("Upload success was acknowledged by the server."),a.success(qq.extend(o,u)))}catch(t){n?(r.log(qq.format("Your server indicated failure in its upload success request response for id {}!",e),"error"),a.failure(c)):(r.log("Upload success was acknowledged by the server."),a.success(u))}}var n,i=[],r={method:"POST",endpoint:null,maxConnections:3,customHeaders:{},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){}};qq.extend(r,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",method:r.method,endpointStore:{get:function(){return r.endpoint}},paramsStore:r.paramsStore,maxConnections:r.maxConnections,customHeaders:r.customHeaders,log:r.log,onComplete:t,cors:r.cors})),qq.extend(this,{sendSuccessRequest:function(e,t){var o=new qq.Promise;return r.log("Submitting upload success request/notification for "+e),n.initTransport(e).withParams(t).send(),i[e]=o,o}})},qq.s3.InitiateMultipartAjaxRequester=function(e){"use strict";function t(e){var t,n=a.getBucket(e),i=a.getHost(e),o={},s=new qq.Promise,u=a.getKey(e);return o["x-amz-acl"]=a.aclStore.get(e),a.reducedRedundancy&&(o[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]=qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE),a.serverSideEncryption&&(o[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]=qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE),o[qq.s3.util.AWS_PARAM_PREFIX+a.filenameParam]=encodeURIComponent(a.getName(e)),qq.each(a.paramsStore.get(e),function(e,t){qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES,e)>=0?o[e]=t:o[qq.s3.util.AWS_PARAM_PREFIX+e]=encodeURIComponent(t)}),t=r.constructStringToSign(r.REQUEST_TYPE.MULTIPART_INITIATE,n,i,u).withContentType(a.getContentType(e)).withHeaders(o),r.getSignature(e,{signatureConstructor:t}).then(s.success,s.failure),s}function n(e,t,n){var i,r,s,u,c,l=o[e],d=new DOMParser,p=d.parseFromString(t.responseText,"application/xml");delete o[e],n?(c=t.status,r=p.getElementsByTagName("Message"),r.length>0&&(u=r[0].textContent)):(i=p.getElementsByTagName("UploadId"),i.length>0?s=i[0].textContent:u="Upload ID missing from request"),void 0===s?(u?a.log(qq.format("Specific problem detected initiating multipart upload request for {}: '{}'.",e,u),"error"):a.log(qq.format("Unexplained error with initiate multipart upload request for {}. Status code {}.",e,c),"error"),l.failure("Problem initiating upload request.",t)):(a.log(qq.format("Initiate multipart upload request successful for {}. Upload ID is {}",e,s)),l.success(s,t))}var i,r,o={},a={filenameParam:"qqfilename",method:"POST",endpointStore:null,paramsStore:null,signatureSpec:null,aclStore:null,reducedRedundancy:!1,serverSideEncryption:!1,maxConnections:3,getContentType:function(e){},getBucket:function(e){},getHost:function(e){},getKey:function(e){},getName:function(e){},log:function(e,t){}};qq.extend(a,e),r=new qq.s3.RequestSigner({endpointStore:a.endpointStore,signatureSpec:a.signatureSpec,cors:a.cors,log:a.log}),i=qq.extend(this,new qq.AjaxRequester({method:a.method,contentType:null,endpointStore:a.endpointStore,maxConnections:a.maxConnections,allowXRequestedWithAndCacheControl:!1,log:a.log,onComplete:n,successfulResponseCodes:{POST:[200]}})),qq.extend(this,{send:function(e){var n=new qq.Promise;return t(e).then(function(t,r){a.log("Submitting S3 initiate multipart upload request for "+e),o[e]=n,i.initTransport(e).withPath(r).withHeaders(t).send()},n.failure),n}})},qq.s3.CompleteMultipartAjaxRequester=function(e){"use strict";function t(e,t,n){var i=new qq.Promise,r=s.getBucket(e),a=s.getHost(e),u=o.constructStringToSign(o.REQUEST_TYPE.MULTIPART_COMPLETE,r,a,s.getKey(e)).withUploadId(t).withContent(n).withContentType("application/xml; charset=UTF-8");return o.getSignature(e,{signatureConstructor:u}).then(i.success,i.failure),i}function n(e,t,n){var i=a[e],r=new DOMParser,o=s.getBucket(e),u=(s.getKey(e),r.parseFromString(t.responseText,"application/xml")),c=u.getElementsByTagName("Bucket"),l=u.getElementsByTagName("Key");delete a[e],s.log(qq.format("Complete response status {}, body = {}",t.status,t.responseText)),n?s.log(qq.format("Complete Multipart Upload request for {} failed with status {}.",e,t.status),"error"):c.length&&l.length?c[0].textContent!==o&&(n=!0,s.log(qq.format("Wrong bucket in response to Complete Multipart Upload request for {}.",e),"error")):(n=!0,s.log(qq.format("Missing bucket and/or key in response to Complete Multipart Upload request for {}.",e),"error")),n?i.failure("Problem combining the file parts!",t):i.success({},t)}function i(e){var t=document.implementation.createDocument(null,"CompleteMultipartUpload",null);return e.sort(function(e,t){return e.part-t.part}),qq.each(e,function(e,n){var i=n.part,r=n.etag,o=t.createElement("Part"),a=t.createElement("PartNumber"),s=t.createTextNode(i),u=t.createTextNode(r),c=t.createElement("ETag");c.appendChild(u),a.appendChild(s),o.appendChild(a),o.appendChild(c),qq(t).children()[0].appendChild(o)}),(new XMLSerializer).serializeToString(t)}var r,o,a={},s={method:"POST",contentType:"text/xml",endpointStore:null,signatureSpec:null,maxConnections:3,getBucket:function(e){},getHost:function(e){},getKey:function(e){},log:function(e,t){}};qq.extend(s,e),o=new qq.s3.RequestSigner({endpointStore:s.endpointStore,signatureSpec:s.signatureSpec,cors:s.cors,log:s.log}),r=qq.extend(this,new qq.AjaxRequester({method:s.method,contentType:"application/xml; charset=UTF-8",endpointStore:s.endpointStore,maxConnections:s.maxConnections,allowXRequestedWithAndCacheControl:!1,log:s.log,onComplete:n,successfulResponseCodes:{POST:[200]}})),qq.extend(this,{send:function(e,n,o){var u=new qq.Promise,c=i(o);return t(e,n,c).then(function(t,n){s.log("Submitting S3 complete multipart upload request for "+e),a[e]=u,delete t["Content-Type"],r.initTransport(e).withPath(n).withHeaders(t).withPayload(c).send()},u.failure),u}})},qq.s3.AbortMultipartAjaxRequester=function(e){"use strict";function t(e,t){var n=new qq.Promise,i=o.getBucket(e),a=o.getHost(e),s=r.constructStringToSign(r.REQUEST_TYPE.MULTIPART_ABORT,i,a,o.getKey(e)).withUploadId(t);return r.getSignature(e,{signatureConstructor:s}).then(n.success,n.failure),n}function n(e,t,n){var i,r=new DOMParser,a=r.parseFromString(t.responseText,"application/xml"),s=a.getElementsByTagName("Error");o.log(qq.format("Abort response status {}, body = {}",t.status,t.responseText)),n?o.log(qq.format("Abort Multipart Upload request for {} failed with status {}.",e,t.status),"error"):s.length?(n=!0,i=a.getElementsByTagName("Message")[0].textContent,o.log(qq.format("Failed to Abort Multipart Upload request for {}. Error: {}",e,i),"error")):o.log(qq.format("Abort MPU request succeeded for file ID {}.",e))}var i,r,o={method:"DELETE",endpointStore:null,signatureSpec:null,maxConnections:3,getBucket:function(e){},getHost:function(e){},getKey:function(e){},log:function(e,t){}};qq.extend(o,e),r=new qq.s3.RequestSigner({endpointStore:o.endpointStore,signatureSpec:o.signatureSpec,cors:o.cors,log:o.log}),i=qq.extend(this,new qq.AjaxRequester({validMethods:["DELETE"],method:o.method,contentType:null,endpointStore:o.endpointStore,maxConnections:o.maxConnections,allowXRequestedWithAndCacheControl:!1,log:o.log,onComplete:n,successfulResponseCodes:{DELETE:[204]}})),qq.extend(this,{send:function(e,n){t(e,n).then(function(t,n){o.log("Submitting S3 Abort multipart upload request for "+e),i.initTransport(e).withPath(n).withHeaders(t).send()})}})},qq.s3.XhrUploadHandler=function(e,t){"use strict";var n=t.getName,i=t.log,r=e.clockDrift,o=200,a=e.getBucket,s=e.getHost,u=e.getKeyName,c=e.filenameParam,l=e.paramsStore,d=e.endpointStore,p=e.aclStore,q=e.objectProperties.reducedRedundancy,f=e.objectProperties.region,h=e.objectProperties.serverSideEncryption,g=e.validation,m=qq.extend({region:f,drift:r},e.signature),_=this,S=e.signature.credentialsProvider,b={combine:function(e){var t=_._getPersistableData(e).uploadId,n=_._getPersistableData(e).etags,i=new qq.Promise;return v.completeMultipart.send(e,t,n).then(i.success,function(t,n){i.failure(w.done(e,n).response,n)}),i},done:function(e,t,n){var i,r=w.response.parse(e,t);r.success&&(i=t.getResponseHeader("ETag"),_._getPersistableData(e).etags||(_._getPersistableData(e).etags=[]),_._getPersistableData(e).etags.push({part:n+1,etag:i}))},initHeaders:function(e,t,n){var i=w.bucket.getName(e),r=w.host.getName(e),o=w.key.urlSafe(e),a=new qq.Promise,s=v.restSignature.constructStringToSign(v.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD,i,r,o).withPartNum(t+1).withContent(n).withUploadId(_._getPersistableData(e).uploadId);return v.restSignature.getSignature(e+"."+t,{signatureConstructor:s}).then(a.success,a.failure),a},put:function(t,n){var r=_._createXhr(t,n),o=_._getChunkData(t,n),a=e.endpointStore.get(t),s=new qq.Promise;return b.initHeaders(t,n,o.blob).then(function(e,u){if(r._cancelled)i(qq.format("Upload of item {}.{} cancelled. Upload will not start after successful signature request.",t,n)),s.failure({error:"Chunk upload cancelled"});else{var c=a+"/"+u;_._registerProgressHandler(t,n,o.size),w.track(t,r,n).then(s.success,s.failure),r.open("PUT",c,!0),qq.each(e,function(e,t){r.setRequestHeader(e,t)}),r.send(o.blob)}},function(){s.failure({error:"Problem signing the chunk!"},r)}),s},send:function(e,t){var n=new qq.Promise;return b.setup(e).then(function(){b.put(e,t).then(n.success,n.failure)},function(e,t){n.failure({error:e},t)}),n},setup:function(e){var t=new qq.Promise,n=_._getPersistableData(e).uploadId,i=new qq.Promise;return n?n instanceof qq.Promise?n.then(function(e){t.success(e)}):t.success(n):(_._getPersistableData(e).uploadId=i,v.initiateMultipart.send(e).then(function(n){_._getPersistableData(e).uploadId=n,i.success(n),t.success(n)},function(n,r){_._getPersistableData(e).uploadId=null,t.failure(n,r),i.failure(n,r)})),t}},v={abortMultipart:new qq.s3.AbortMultipartAjaxRequester({endpointStore:d,signatureSpec:m,cors:e.cors,log:i,getBucket:function(e){return w.bucket.getName(e)},getHost:function(e){return w.host.getName(e)},getKey:function(e){return w.key.urlSafe(e)}}),completeMultipart:new qq.s3.CompleteMultipartAjaxRequester({endpointStore:d,signatureSpec:m,cors:e.cors,log:i,getBucket:function(e){return w.bucket.getName(e)},getHost:function(e){return w.host.getName(e)},getKey:function(e){return w.key.urlSafe(e)}}),initiateMultipart:new qq.s3.InitiateMultipartAjaxRequester({filenameParam:c,endpointStore:d,paramsStore:l,signatureSpec:m,aclStore:p,reducedRedundancy:q,serverSideEncryption:h,cors:e.cors,log:i,getContentType:function(e){return _._getMimeType(e)},getBucket:function(e){return w.bucket.getName(e)},getHost:function(e){return w.host.getName(e)},getKey:function(e){return w.key.urlSafe(e)},getName:function(e){return n(e)}}),policySignature:new qq.s3.RequestSigner({expectingPolicy:!0,signatureSpec:m,cors:e.cors,log:i}),restSignature:new qq.s3.RequestSigner({endpointStore:d,signatureSpec:m,cors:e.cors,log:i})},y={initParams:function(e){var t=l.get(e);return t[c]=n(e),qq.s3.util.generateAwsParams({endpoint:d.get(e),clockDrift:r,params:t,type:_._getMimeType(e),bucket:w.bucket.getName(e),key:_.getThirdPartyFileId(e),accessKey:S.get().accessKey,sessionToken:S.get().sessionToken,acl:p.get(e),expectedStatus:o,minFileSize:g.minSizeLimit,maxFileSize:g.maxSizeLimit,reducedRedundancy:q,region:f,serverSideEncryption:h,signatureVersion:m.version,log:i},qq.bind(v.policySignature.getSignature,this,e))},send:function(e){var t=new qq.Promise,n=_._createXhr(e),r=_.getFile(e);return _._registerProgressHandler(e),w.track(e,n).then(t.success,t.failure),y.setup(e,n,r).then(function(t){i("Sending upload request for "+e),n.send(t)},t.failure),t},setup:function(e,t,n){var i=new FormData,r=d.get(e),o=r,a=new qq.Promise;return y.initParams(e).then(function(e){t.open("POST",o,!0),qq.obj2FormData(e,i),i.append("file",n),a.success(i)},function(e){a.failure({error:e})}),a}},w={bucket:{promise:function(e){var t=new qq.Promise,n=_._getFileState(e).bucket;return n?t.success(n):a(e).then(function(n){_._getFileState(e).bucket=n,t.success(n)},t.failure),t},getName:function(e){return _._getFileState(e).bucket}},host:{promise:function(e){var t=new qq.Promise,n=_._getFileState(e).host;return n?t.success(n):s(e).then(function(n){_._getFileState(e).host=n,t.success(n)},t.failure),t},getName:function(e){return _._getFileState(e).host}},done:function(e,t){var n=w.response.parse(e,t),r=n.success!==!0;return r&&w.response.shouldReset(n.code)&&(i("This is an unrecoverable error, we must restart the upload entirely on the next retry attempt.","error"),n.reset=!0),{success:!r,response:n}},key:{promise:function(e){var t=new qq.Promise,i=_.getThirdPartyFileId(e);return null==i?(_._setThirdPartyFileId(e,t),u(e,n(e)).then(function(n){_._setThirdPartyFileId(e,n),t.success(n)},function(n){_._setThirdPartyFileId(e,null),t.failure(n)})):qq.isGenericPromise(i)?i.then(t.success,t.failure):t.success(i),t},urlSafe:function(e){var t=_.getThirdPartyFileId(e);return qq.s3.util.uriEscapePath(t)}},response:{parse:function(e,t){var n,r={};try{i(qq.format("Received response status {} with body: {}",t.status,t.responseText)),t.status===o?r.success=!0:(n=w.response.parseError(t.responseText),n&&(r.error=n.message,r.code=n.code))}catch(e){i("Error when attempting to parse xhr response text ("+e.message+")","error")}return r},parseError:function(e){var t,n,i=new DOMParser,r=i.parseFromString(e,"application/xml"),o=r.getElementsByTagName("Error"),a={};if(o.length)return t=r.getElementsByTagName("Code"),n=r.getElementsByTagName("Message"),n.length&&(a.message=n[0].textContent),t.length&&(a.code=t[0].textContent),a},shouldReset:function(e){return"EntityTooSmall"===e||"InvalidPart"===e||"InvalidPartOrder"===e||"NoSuchUpload"===e}},start:function(e,t){var n=new qq.Promise;return w.key.promise(e).then(function(){w.bucket.promise(e).then(function(){w.host.promise(e).then(function(){null==t?y.send(e).then(n.success,n.failure):b.send(e,t).then(n.success,n.failure)})})},function(e){n.failure({error:e})}),n},track:function(e,t,n){var i=new qq.Promise;return t.onreadystatechange=function(){if(4===t.readyState){var r;null==n?(r=w.done(e,t),i[r.success?"success":"failure"](r.response,t)):(b.done(e,t,n),r=w.done(e,t),i[r.success?"success":"failure"](r.response,t))}},i}};qq.extend(this,{uploadChunk:w.start,uploadFile:w.start}),qq.extend(this,new qq.XhrUploadHandler({options:qq.extend({namespace:"s3"},e),proxy:qq.extend({getEndpoint:e.endpointStore.get},t)})),qq.override(this,function(e){return{expunge:function(t){var n=_._getPersistableData(t)&&_._getPersistableData(t).uploadId,i=_._maybeDeletePersistedChunkData(t);void 0!==n&&i&&v.abortMultipart.send(t,n),e.expunge(t)},finalizeChunks:function(e){return b.combine(e)},_getLocalStorageId:function(t){var n=e._getLocalStorageId(t),i=w.bucket.getName(t);return n+"-"+i}}})},qq.s3.FormUploadHandler=function(e,t){"use strict";function n(t,n){var i,r,o,a=(e.endpointStore.get(t),s._getFileState(t).bucket);try{if(i=n.contentDocument||n.contentWindow.document,r=i.body.innerHTML,o=qq.s3.util.parseIframeResponse(n),o.bucket===a&&o.key===qq.s3.util.encodeQueryStringParam(s.getThirdPartyFileId(t)))return!0;p("Response from AWS included an unexpected bucket or key name.","error")}catch(e){p("Error when attempting to parse form upload response ("+e.message+")","error")}return!1}function i(e){var t=g.get(e);return t[h]=l(e),qq.s3.util.generateAwsParams({endpoint:m.get(e),clockDrift:u,params:t,bucket:s._getFileState(e).bucket,key:s.getThirdPartyFileId(e),accessKey:C.get().accessKey,sessionToken:C.get().sessionToken,acl:_.get(e),minFileSize:y.minSizeLimit,maxFileSize:y.maxSizeLimit,successRedirectUrl:x,reducedRedundancy:S,region:b,serverSideEncryption:v,signatureVersion:w.version,log:p},qq.bind(P.getSignature,this,e))}function r(t,n){var r=new qq.Promise,o="POST",u=e.endpointStore.get(t),c=l(t);return i(t).then(function(e){var t=s._initFormForUpload({method:o,endpoint:u,params:e,paramsInBody:!0,targetName:n.name});r.success(t)},function(e){r.failure(e),a(t,n,c,{error:e})}),r}function o(e){var t=s._createIframe(e),i=s.getInput(e),o=new qq.Promise;return r(e,t).then(function(r){r.appendChild(i),s._attachLoadEvent(t,function(i){p("iframe loaded"),i?i.success===!1&&(p("Amazon likely rejected the upload request","error"),o.failure(i)):(i={},i.success=n(e,t),i.success===!1?(p("A success response was received by Amazon, but it was invalid in some way.","error"),o.failure(i)):(qq.extend(i,qq.s3.util.parseIframeResponse(t)),o.success(i))),a(e,t)}),p("Sending upload request for "+e),r.submit(),qq(r).remove()},o.failure),o}function a(e,t){s._detachLoadEvent(e),t&&qq(t).remove()}var s=this,u=e.clockDrift,c=t.onUuidChanged,l=t.getName,d=t.getUuid,p=t.log,q=e.getBucket,f=e.getKeyName,h=e.filenameParam,g=e.paramsStore,m=e.endpointStore,_=e.aclStore,S=e.objectProperties.reducedRedundancy,b=e.objectProperties.region,v=e.objectProperties.serverSideEncryption,y=e.validation,w=e.signature,x=e.iframeSupport.localBlankPagePath,C=e.signature.credentialsProvider,P=new qq.s3.RequestSigner({signatureSpec:w,cors:e.cors,log:p});if(void 0===x)throw new Error("successRedirectEndpoint MUST be defined if you intend to use browsers that do not support the File API!");qq.extend(this,new qq.FormUploadHandler({options:{isCors:!1,inputName:"file"},proxy:{onCancel:e.onCancel,onUuidChanged:c,getName:l,getUuid:d,log:p}})),qq.extend(this,{uploadFile:function(e){var t=l(e),n=new qq.Promise;return s.getThirdPartyFileId(e)?s._getFileState(e).bucket?o(e).then(n.success,n.failure):q(e).then(function(t){s._getFileState(e).bucket=t,o(e).then(n.success,n.failure)}):f(e,t).then(function(t){q(e).then(function(i){s._getFileState(e).bucket=i,s._setThirdPartyFileId(e,t),o(e).then(n.success,n.failure)},function(e){n.failure({error:e})})},function(e){n.failure({error:e})}),n}})},qq.azure=qq.azure||{},qq.azure.util=qq.azure.util||function(){"use strict";return{AZURE_PARAM_PREFIX:"x-ms-meta-",_paramNameMatchesAzureParameter:function(e){switch(e){case"Cache-Control":case"Content-Disposition":case"Content-Encoding":case"Content-MD5":case"x-ms-blob-content-encoding":case"x-ms-blob-content-disposition":case"x-ms-blob-content-md5":case"x-ms-blob-cache-control":return!0;default:return!1}},_getPrefixedParamName:function(e){return qq.azure.util._paramNameMatchesAzureParameter(e)?e:qq.azure.util.AZURE_PARAM_PREFIX+e},getParamsAsHeaders:function(e){var t={};return qq.each(e,function(e,n){var i=qq.azure.util._getPrefixedParamName(e),r=null;qq.isFunction(n)?r=String(n()):qq.isObject(n)?qq.extend(t,qq.azure.util.getParamsAsHeaders(n)):r=String(n),null!==r&&(qq.azure.util._paramNameMatchesAzureParameter(e)?t[i]=r:t[i]=encodeURIComponent(r))}),t},parseAzureError:function(e,t){var n,i,r=new DOMParser,o=r.parseFromString(e,"application/xml"),a=o.getElementsByTagName("Error")[0],s={};if(t("Received error response: "+e,"error"),a)return i=a.getElementsByTagName("Message")[0],i&&(s.message=i.textContent),n=a.getElementsByTagName("Code")[0],n&&(s.code=n.textContent),t("Parsed Azure error: "+JSON.stringify(s),"error"),s}}}(),function(){"use strict";qq.nonTraditionalBasePublicApi={setUploadSuccessParams:function(e,t){this._uploadSuccessParamsStore.set(e,t)},setUploadSuccessEndpoint:function(e,t){this._uploadSuccessEndpointStore.set(e,t)}},qq.nonTraditionalBasePrivateApi={_onComplete:function(e,t,n,i){var r,o,a=!!n.success,s=this,u=arguments,c=this._uploadSuccessEndpointStore.get(e),l=this._options.uploadSuccess.customHeaders,d=this._options.uploadSuccess.method,p=this._options.cors,q=new qq.Promise,f=this._uploadSuccessParamsStore.get(e),h=this._paramsStore.get(e),g=function(t){delete s._failedSuccessRequestCallbacks[e],qq.extend(n,t),qq.FineUploaderBasic.prototype._onComplete.apply(s,u),q.success(t)},m=function(o){var a=r;qq.extend(n,o),n&&n.reset&&(a=null),a?s._failedSuccessRequestCallbacks[e]=a:delete s._failedSuccessRequestCallbacks[e],s._onAutoRetry(e,t,n,i,a)||(qq.FineUploaderBasic.prototype._onComplete.apply(s,u),q.failure(o))};return a&&c?(o=new qq.UploadSuccessAjaxRequester({endpoint:c,method:d,customHeaders:l,cors:p,log:qq.bind(this.log,this)}),qq.extend(f,s._getEndpointSpecificParams(e,n,i),!0),h&&qq.extend(f,h,!0),r=qq.bind(function(){o.sendSuccessRequest(e,f).then(g,m)},s),r(),q):qq.FineUploaderBasic.prototype._onComplete.apply(this,arguments)},_manualRetry:function(e){var t=this._failedSuccessRequestCallbacks[e];return qq.FineUploaderBasic.prototype._manualRetry.call(this,e,t)}}}(),function(){"use strict";qq.azure.FineUploaderBasic=function(e){if(!qq.supportedFeatures.ajaxUploading)throw new qq.Error("Uploading directly to Azure is not possible in this browser.");var t={signature:{endpoint:null,customHeaders:{}},blobProperties:{name:"uuid"},uploadSuccess:{endpoint:null,method:"POST",params:{},customHeaders:{}},chunking:{partSize:4e6,minFileSize:4000001}};qq.extend(t,e,!0),qq.FineUploaderBasic.call(this,t),this._uploadSuccessParamsStore=this._createStore(this._options.uploadSuccess.params),this._uploadSuccessEndpointStore=this._createStore(this._options.uploadSuccess.endpoint),this._failedSuccessRequestCallbacks={},this._cannedBlobNames={}},qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,{getBlobName:function(e){return null==this._cannedBlobNames[e]?this._handler.getThirdPartyFileId(e):this._cannedBlobNames[e]},_getEndpointSpecificParams:function(e){return{blob:this.getBlobName(e),uuid:this.getUuid(e),name:this.getName(e),container:this._endpointStore.get(e)}},_createUploadHandler:function(){return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,{signature:this._options.signature,onGetBlobName:qq.bind(this._determineBlobName,this),deleteBlob:qq.bind(this._deleteBlob,this,!0)},"azure")},_determineBlobName:function(e){var t=this._options.blobProperties.name,n=this.getUuid(e),i=this.getName(e),r=qq.getExtension(i),o=n;if(!qq.isString(t))return t.call(this,e);switch(t){case"uuid":return void 0!==r&&(o+="."+r),(new qq.Promise).success(o);case"filename":return(new qq.Promise).success(i);default:return new qq.Promise.failure("Invalid blobName option value - "+t)}},_addCannedFile:function(e){var t;if(null==e.blobName)throw new qq.Error("Did not find blob name property in server session response. This is required!");return t=qq.FineUploaderBasic.prototype._addCannedFile.apply(this,arguments),this._cannedBlobNames[t]=e.blobName,t},_deleteBlob:function(e,t){var n=this,i={},r={get:function(e){return n._endpointStore.get(e)+"/"+n.getBlobName(e)}},o={get:function(e){return i[e]}},a=function(e,t){i[e]=t,u.send(e)},s=function(t,i,r){e?(n.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS","error"),qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t))):(n._onDeleteComplete(t,r,!0),n._options.callbacks.onDeleteComplete(t,r,!0))},u=new qq.azure.DeleteBlob({endpointStore:o,log:qq.bind(n.log,n),onDelete:function(e){n._onDelete(e),n._options.callbacks.onDelete(e)},onDeleteComplete:function(t,r,o){delete i[t],o&&(e?n.log("Will cancel upload, but failed to remove uncommitted parts from Azure.","error"):qq.azure.util.parseAzureError(r.responseText,qq.bind(n.log,n))),e?(qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t)),n.log("Deleted uncommitted blob chunks for "+t)):(n._onDeleteComplete(t,r,o),n._options.callbacks.onDeleteComplete(t,r,o))}}),c=new qq.azure.GetSas({cors:this._options.cors,customHeaders:this._options.signature.customHeaders,endpointStore:{get:function(){return n._options.signature.endpoint}},restRequestVerb:u.method,log:qq.bind(n.log,n)});c.request(t,r.get(t)).then(qq.bind(a,n,t),qq.bind(s,n,t))},_createDeleteHandler:function(){var e=this;return{sendDelete:function(t,n){e._deleteBlob(!1,t)}}}})}(),qq.azure.XhrUploadHandler=function(e,t){"use strict";function n(e){var t=new qq.Promise;return r(e).then(function(n){var i=a._getMimeType(e),r=a._getPersistableData(e).blockIdEntries;S.putBlockList.send(e,n,r,i,function(t){a._registerXhr(e,null,t,S.putBlockList)}).then(function(n){s("Success combining chunks for id "+e),t.success({},n)},function(n){s("Attempt to combine chunks failed for id "+e,"error"),o(n,t)})},t.failure),t}function i(e){var t=c.get(e),n=new qq.Promise,i=function(i){a._setThirdPartyFileId(e,i),n.success(t+"/"+i)},r=function(e){n.failure(e)};return h(e).then(i,r),n}function r(e,t){var n=null==t?e:e+"."+t,r=new qq.Promise,o=function(e){s("GET SAS request succeeded."),r.success(e)},a=function(e,t){s("GET SAS request failed: "+e,"error"),r.failure({error:"Problem communicating with local server"},t)},u=function(e){S.getSasForPutBlobOrBlock.request(n,e).then(o,a)},c=function(t){s(qq.format("Failed to determine blob name for ID {} - {}",e,t),"error"),r.failure({error:t})};return i(e).then(u,c),r}function o(e,t){var n=qq.azure.util.parseAzureError(e.responseText,s),i="Problem sending file to Azure";t.failure({error:i,azureError:n&&n.message,reset:403===e.status})}var a=this,s=t.log,u=e.cors,c=e.endpointStore,l=e.paramsStore,d=e.signature,p=e.filenameParam,q=e.chunking.minFileSize,f=e.deleteBlob,h=e.onGetBlobName,g=t.getName,m=t.getSize,_=function(e){var t=l.get(e);return t[p]=g(e),t},S={putBlob:new qq.azure.PutBlob({getBlobMetadata:_,log:s}),putBlock:new qq.azure.PutBlock({log:s}),putBlockList:new qq.azure.PutBlockList({getBlobMetadata:_,log:s}),getSasForPutBlobOrBlock:new qq.azure.GetSas({cors:u,customHeaders:d.customHeaders,endpointStore:{get:function(){return d.endpoint}},log:s,restRequestVerb:"PUT"})};qq.extend(this,{uploadChunk:function(e,t){var n=new qq.Promise;return r(e,t).then(function(i){var r=a._createXhr(e,t),u=a._getChunkData(e,t);a._registerProgressHandler(e,t,u.size),a._registerXhr(e,t,r,S.putBlock),S.putBlock.upload(e+"."+t,r,i,t,u.blob).then(function(t){a._getPersistableData(e).blockIdEntries||(a._getPersistableData(e).blockIdEntries=[]),a._getPersistableData(e).blockIdEntries.push(t),s("Put Block call succeeded for "+e),n.success({},r)},function(){s(qq.format("Put Block call failed for ID {} on part {}",e,t),"error"),o(r,n)})},n.failure),n},uploadFile:function(e){var t=new qq.Promise,n=a.getFile(e);return r(e).then(function(i){var r=a._createXhr(e);a._registerProgressHandler(e),S.putBlob.upload(e,r,i,n).then(function(){s("Put Blob call succeeded for "+e),t.success({},r)},function(){s("Put Blob call failed for "+e,"error"),o(r,t)})},t.failure),t}}),qq.extend(this,new qq.XhrUploadHandler({options:qq.extend({namespace:"azure"},e),proxy:qq.extend({getEndpoint:e.endpointStore.get},t)})),qq.override(this,function(e){return{expunge:function(t){var n=a._wasCanceled(t),i=a._getPersistableData(t),r=i&&i.blockIdEntries||[];n&&r.length>0&&f(t),e.expunge(t)},finalizeChunks:function(e){return n(e)},_shouldChunkThisFile:function(t){var n=e._shouldChunkThisFile(t);return n&&m(t)>=q}}})},qq.azure.GetSas=function(e){"use strict";function t(e,t,n){var i=r[e];n?i.failure("Received response code "+t.status,t):t.responseText.length?i.success(t.responseText):i.failure("Empty response.",t),delete r[e]}var n,i={cors:{expected:!1,sendCredentials:!1},customHeaders:{},restRequestVerb:"PUT",endpointStore:null,
+log:function(e,t){}},r={};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",successfulResponseCodes:{GET:[200]},contentType:null,customHeaders:i.customHeaders,endpointStore:i.endpointStore,cors:i.cors,log:i.log,onComplete:t})),qq.extend(this,{request:function(e,t){var o=new qq.Promise,a=i.restRequestVerb;return i.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.",a,e)),r[e]=o,n.initTransport(e).withParams({bloburi:t,_method:a}).withCacheBuster().send(),o}})},qq.UploadSuccessAjaxRequester=function(e){"use strict";function t(e,t,n){var o,a=i[e],s=t.responseText,u={success:!0},c={success:!1};delete i[e],r.log(qq.format("Received the following response body to an upload success request for id {}: {}",e,s));try{o=qq.parseJson(s),n||o&&(o.error||o.success===!1)?(r.log("Upload success request was rejected by the server.","error"),a.failure(qq.extend(o,c))):(r.log("Upload success was acknowledged by the server."),a.success(qq.extend(o,u)))}catch(t){n?(r.log(qq.format("Your server indicated failure in its upload success request response for id {}!",e),"error"),a.failure(c)):(r.log("Upload success was acknowledged by the server."),a.success(u))}}var n,i=[],r={method:"POST",endpoint:null,maxConnections:3,customHeaders:{},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){}};qq.extend(r,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",method:r.method,endpointStore:{get:function(){return r.endpoint}},paramsStore:r.paramsStore,maxConnections:r.maxConnections,customHeaders:r.customHeaders,log:r.log,onComplete:t,cors:r.cors})),qq.extend(this,{sendSuccessRequest:function(e,t){var o=new qq.Promise;return r.log("Submitting upload success request/notification for "+e),n.initTransport(e).withParams(t).send(),i[e]=o,o}})},qq.azure.DeleteBlob=function(e){"use strict";var t,n="DELETE",i={endpointStore:{},onDelete:function(e){},onDeleteComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[202],e}(),contentType:null,endpointStore:i.endpointStore,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete})),qq.extend(this,{method:n,send:function(e){return i.log("Submitting Delete Blob request for "+e),t.initTransport(e).send()}})},qq.azure.PutBlob=function(e){"use strict";var t,n="PUT",i={getBlobMetadata:function(e){},log:function(e,t){}},r={},o={},a={get:function(e){return r[e]}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[201],e}(),contentType:null,customHeaders:function(e){var t=i.getBlobMetadata(e),n=qq.azure.util.getParamsAsHeaders(t);return n["x-ms-blob-type"]="BlockBlob",n},endpointStore:a,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onComplete:function(e,t,n){var i=o[e];delete r[e],delete o[e],n?i.failure():i.success()}})),qq.extend(this,{method:n,upload:function(e,n,a,s){var u=new qq.Promise;return i.log("Submitting Put Blob request for "+e),o[e]=u,r[e]=a,t.initTransport(e).withPayload(s).withHeaders({"Content-Type":s.type}).send(n),u}})},qq.azure.PutBlock=function(e){"use strict";function t(e){var t=5,n=new Array(t+1).join("0"),i=(n+e).slice(-t);return btoa(i)}var n,i="PUT",r={},o={},a={log:function(e,t){}},s={},u={get:function(e){return s[e]}};qq.extend(a,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),contentType:null,endpointStore:u,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:a.log,onComplete:function(e,t,n){var i=o[e],a=r[e];delete s[e],delete o[e],delete r[e],n?i.failure():i.success(a)}})),qq.extend(this,{method:i,upload:function(e,i,u,c,l){var d=new qq.Promise,p=t(c);return o[e]=d,a.log(qq.format("Submitting Put Block request for {} = part {}",e,c)),s[e]=qq.format("{}&comp=block&blockid={}",u,encodeURIComponent(p)),r[e]={part:c,id:p},n.initTransport(e).withPayload(l).send(i),d}})},qq.azure.PutBlockList=function(e){"use strict";function t(e){var t=document.implementation.createDocument(null,"BlockList",null);return e.sort(function(e,t){return e.part-t.part}),qq.each(e,function(e,n){var i=t.createElement("Latest"),r=t.createTextNode(n.id);i.appendChild(r),qq(t).children()[0].appendChild(i)}),(new XMLSerializer).serializeToString(t)}var n,i="PUT",r={},o={getBlobMetadata:function(e){},log:function(e,t){}},a={},s={get:function(e){return a[e]}};qq.extend(o,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),customHeaders:function(e){var t=o.getBlobMetadata(e);return qq.azure.util.getParamsAsHeaders(t)},contentType:"text/plain",endpointStore:s,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:o.log,onSend:function(){},onComplete:function(e,t,n){var i=r[e];delete a[e],delete r[e],n?i.failure(t):i.success(t)}})),qq.extend(this,{method:i,send:function(e,i,s,u,c){var l,d=new qq.Promise,p=t(s);return r[e]=d,o.log(qq.format("Submitting Put Block List request for {}",e)),a[e]=qq.format("{}&comp=blocklist",i),l=n.initTransport(e).withPayload(p).withHeaders({"x-ms-blob-content-type":u}).send(),c(l),d}})}}(window,window);
+//# sourceMappingURL=all.fine-uploader.core.min.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.core.min.js.map b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.core.min.js.map
new file mode 100644
index 000000000000..695f176f8bd0
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.core.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/traditional/traditional.form.upload.handler.js","../client/js/traditional/traditional.xhr.upload.handler.js","../client/js/traditional/all-chunks-done.ajax.requester.js","../client/js/third-party/crypto-js/core.js","../client/js/third-party/crypto-js/enc-base64.js","../client/js/third-party/crypto-js/hmac.js","../client/js/third-party/crypto-js/sha1.js","../client/js/third-party/crypto-js/sha256.js","../client/js/third-party/crypto-js/lib-typedarrays.js","../client/js/s3/util.js","../client/js/non-traditional-common/uploader.basic.api.js","../client/js/s3/uploader.basic.js","../client/js/s3/request-signer.js","../client/js/uploadsuccess.ajax.requester.js","../client/js/s3/multipart.initiate.ajax.requester.js","../client/js/s3/multipart.complete.ajax.requester.js","../client/js/s3/multipart.abort.ajax.requester.js","../client/js/s3/s3.xhr.upload.handler.js","../client/js/s3/s3.form.upload.handler.js","../client/js/azure/util.js","../client/js/azure/uploader.basic.js","../client/js/azure/azure.xhr.upload.handler.js","../client/js/azure/get-sas.js","../client/js/azure/rest/delete-blob.js","../client/js/azure/rest/put-blob.js","../client/js/azure/rest/put-block.js","../client/js/azure/rest/put-block-list.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","intArray","mimeString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","testSupportsFileInputElement","tempInput","supported","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","createInput","BUTTON_ID_ATTR_NAME","buttonId","options","title","self","setMultiple","folders","acceptFiles","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","disposeSupport","onChange","hoverClass","focusClass","ios8BrowserCrashWorkaround","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","byUuid","getDataByStatus","status","statusResults","statuses","index","statusEnum","statusResultIndexes","byStatus","dataIndex","byProxyGroupId","byBatchId","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","params","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","_options","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","fileOrUrl","promiseToReturn","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","callbacks","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","toUpperCase","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","allowedExtensions","accept","validation","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","namespace","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","replacement","extensionsForMessage","placeholderMatch","messages","names","validationBase","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","requestData","dequeue","nextId","queue","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","mandatedParams","optXhr","url","payload","onSend","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","shouldParamsBeInQueryString","contentType","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","acceptHeader","setRequestHeader","allowXRequestedWithAndCacheControl","responseCode","successfulResponseCodes","prepareToSend","validMethods","DELETE","PATCH","POST","PUT","GET","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","preventRetryResponse","controller","chunkingPossible","concurrentChunkingPossible","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","inProgressIdx","responseToReport","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","expungeFile","detachLoadEvents","isCors","postMessageCallbackTimers","corsMessageReceiver","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","onloadCallbacks","onloadCallback","_parseJsonResponse","_detachLoadEvent","formHandlerInstanceId","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","xhrId","ajaxRequester","_getAjaxRequester","chunkFiles","resumeEnabled","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","getMandatedParams","_method","requester","detectSubsampling","img","ctx","iw","naturalWidth","ih","naturalHeight","width","getContext","drawImage","getImageData","detectVerticalSquash","alpha","ratio","sy","ey","py","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","tmpCtx","sx","dx","d","tmpCanvas","vertSquashRatio","dw","dh","dy","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","opt","imgWidth","imgHeight","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","el","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetProtocol","targetHostname","targetPort","targetAnchor","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","TAG_IDS","vals","tagValHex","tagValLength","idHex","tagsToFindIdx","TAG_INFO","274","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","chr1","chr2","enc1","enc2","enc3","output","chr3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","isImage","registerPasteHandler","detachPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","determineNewEndpoint","formEl","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","_form2Obj","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","getIframeContentJson","doc","innerHtml","contentWindow","nodeValue","createForm","responseFromMessage","multipart","addChunkingSpecificParams","allChunksDoneRequester","AllChunksDoneAjaxRequester","createReadyStateChangedHandler","onUploadOrChunkComplete","getChunksCompleteParams","isErrorUploadResponse","parseResponse","sendChunksCompleteRequest","complete","setParamsAndGetEntityToSend","setUploadHeaders","extraHeaders","toSend","promises","endpointHandler","CryptoJS","C","C_lib","lib","Base","F","overrides","subtype","mixIn","init","$super","instance","properties","propertyName","clone","WordArray","words","sigBytes","encoder","Hex","wordArray","thisWords","thatWords","thisSigBytes","thatSigBytes","clamp","thatByte","nBytes","C_enc","enc","hexChars","bite","hexStr","hexStrLength","Latin1","latin1Chars","fromCharCode","latin1Str","latin1StrLength","Utf8","decodeURIComponent","escape","utf8Str","unescape","BufferedBlockAlgorithm","_data","_nDataBytes","_append","_process","doFlush","dataWords","dataSigBytes","blockSize","blockSizeBytes","nBlocksReady","_minBufferSize","nWordsReady","nBytesReady","min","_doProcessBlock","processedWords","C_algo","Hasher","cfg","_doReset","update","messageUpdate","hash","_doFinalize","_createHelper","hasher","_createHmacHelper","HMAC","algo","Base64","map","_map","base64Chars","byte1","byte2","byte3","triplet","j","paddingChar","base64Str","base64StrLength","paddingIndex","bits1","bits2","_hasher","hasherBlockSize","hasherBlockSizeBytes","oKey","_oKey","iKey","_iKey","oKeyWords","iKeyWords","innerHash","hmac","W","SHA1","_hash","M","H","n","t","nBitsTotal","nBitsLeft","floor","HmacSHA1","K","isPrime","sqrtN","factor","getFractionalBits","nPrime","SHA256","f","g","h","gamma0x","gamma0","gamma1x","gamma1","ch","maj","sigma0","sigma1","t1","t2","HmacSHA256","superInit","subInit","typedArray","Int8Array","Uint8ClampedArray","Int16Array","Uint16Array","Int32Array","Uint32Array","Float32Array","Float64Array","byteOffset","byteLength","typedArrayByteLength","s3","util","ALGORITHM_PARAM_NAME","AWS_PARAM_PREFIX","CREDENTIAL_PARAM_NAME","DATE_PARAM_NAME","REDUCED_REDUNDANCY_PARAM_NAME","REDUCED_REDUNDANCY_PARAM_VALUE","SERVER_SIDE_ENCRYPTION_PARAM_NAME","SERVER_SIDE_ENCRYPTION_PARAM_VALUE","SESSION_TOKEN_PARAM_NAME","V4_ALGORITHM_PARAM_VALUE","V4_SIGNATURE_PARAM_NAME","CASE_SENSITIVE_PARAM_NAMES","UNSIGNABLE_REST_HEADER_NAMES","UNPREFIXED_PARAM_NAMES","getBucket","bucket","patterns","pattern","_getPrefixedParamName","getPolicy","policy","conditions","date","drift","clockDrift","accessKey","acl","expectedStatus","sessionToken","successRedirectUrl","getSuccessRedirectAbsoluteUrl","minFileSize","maxFileSize","reducedRedundancy","region","serverSideEncryption","signatureVersion","expiration","getPolicyExpirationDate","Content-Type","success_action_status","success_action_redirect","getV4CredentialsString","getV4PolicyDate","awsParamName","enforceSizeLimits","refreshPolicyCredentials","newSessionToken","sessionTokenFound","oldCondIdx","oldCondObj","oldCondName","oldCondVal","generateAwsParams","signPolicyCallback","policyJson","awsParams","customParams","AWSAccessKeyId","policyAndSignature","updatedAccessKey","updatedSessionToken","signature","minSize","adjustedMinSize","adjustedMaxSize","adjustedDate","getPolicyDate","getCredentialsDate","getUTCFullYear","getUTCMonth","getUTCDate","_minutesToAdd_","pad","minutesToAdd","setMinutes","getMinutes","toISOString","number","getUTCHours","getUTCMinutes","getUTCSeconds","getUTCMilliseconds","parseIframeResponse","queryString","search","etag","targetAnchorContainer","encodeQueryStringParam","percentEncoded","uriEscape","uriEscapePath","nonTraditionalBasePublicApi","setUploadSuccessParams","_uploadSuccessParamsStore","setUploadSuccessEndpoint","_uploadSuccessEndpointStore","nonTraditionalBasePrivateApi","submitSuccessRequest","successAjaxRequester","onCompleteArgs","successEndpoint","successCustomHeaders","uploadSuccess","successMethod","uploadSuccessParams","fileParams","onSuccessFromServer","successRequestResult","_failedSuccessRequestCallbacks","onFailureFromServer","UploadSuccessAjaxRequester","_getEndpointSpecificParams","sendSuccessRequest","successRequestCallback","objectProperties","host","credentials","secretKey","iframeSupport","localBlankPagePath","onCredentialsExpired","setCredentials","_currentCredentials","_aclStore","_cannedKeys","_cannedBuckets","_buckets","_hosts","getKey","ignoreEmpty","setAcl","aclStore","_determineBucket","getHost","_determineHost","getKeyName","_determineKeyName","maxSizeLimit","oldParams","modifiedParams","paramName","credentialsProvider","onExpired","updateCredentials","_determineObjectPropertyValue","property","maybe","keynameLogic","onGetKeynameFailure","onGetKeynameSuccess","keyname","keynameToUse","_handleKeynameFunction","keynameFunc","successCallback","failureCallback","getResponseHeader","s3Key","s3Bucket","RequestSigner","handleSignatureReceived","responseJson","pendingSignatureData","pendingSignatures","signatureConstructor","invalid","expectingPolicy","generateHeaders","getStringToSignArtifacts","requestInfo","endOfUrl","signatureSpec","toSign","headerNames","headersStr","generateStringToSign","contentMd5","headerIndexesToRemove","headerName","headerIdx","hashedContent","v2","getStringToSign","v4","signedHeaders","getSignedHeaders","hashed","toSignRaw","raw","thisSignatureRequester","REQUEST_TYPE","MULTIPART_ABORT","uploadId","MULTIPART_INITIATE","MULTIPART_COMPLETE","MULTIPART_UPLOAD","partNum","getEncodedHashedPayload","content","Host","determineSignatureClientSide","toBeSigned","signatureEffort","updatedHeaders","getHeaders","getToSign","signatureArtifacts","signApiRequest","stringToSign","signPolicy","Authorization","getRequestDate","getEndOfUrl","headersWordArray","headersHmacSha1","headersHmacSha1Base64","policyStr","policyWordArray","base64Policy","policyHmacSha1","policyHmacSha1Base64","getCanonicalQueryString","endOfUri","encodedQueryParams","encodedQueryParamNames","queryStrings","queryParamIdx","canonicalQueryString","nameAndVal","paramVal","forEach","encodedQueryParamName","getCanonicalRequest","getCanonicalUri","onloadend","DONE","getScope","canonicalRequest","hashedRequest","scope","stringToSignTemplate","dateKey","dateRegionKey","dateRegionServiceKey","signingKey","headersPattern","matches","credentialPattern","credentialCondition","credential","condition","getSignature","queryParams","stringToSignRaw","constructStringToSign","artifacts","theHeaders","withUploadId","theUploadId","withContent","theContent","withContentType","theContentType","withPartNum","thePartNum","toUTCString","_artifacts_","handleSuccessResponse","parsedResponse","pendingRequests","successIndicator","failureIndicator","InitiateMultipartAjaxRequester","getSignatureAjaxRequester","getContentType","handleInitiateRequestComplete","uploadIdElements","messageElements","pendingInitiateRequests","domParser","DOMParser","responseDoc","parseFromString","CompleteMultipartAjaxRequester","handleCompleteRequestComplete","pendingCompleteRequests","bucketEls","keyEls","getCompleteRequestBody","etagEntries","implementation","createDocument","etagEntry","partEl","partNumEl","partNumTextEl","createTextNode","etagTextEl","etagEl","XMLSerializer","serializeToString","AbortMultipartAjaxRequester","handleAbortRequestComplete","awsErrorMsg","errorEls","onGetBucket","onGetHost","onGetKeyName","combine","etagMap","etags","requesters","completeMultipart","initHeaders","urlSafe","restSignature","put","domain","track","setup","uploadIdPromise","initiateMultipart","abortMultipart","policySignature","initParams","cachedBucket","cachedHost","shouldReset","keyName","encodedKey","parsedErrorProps","parseError","awsResponseXml","codeEls","messageEls","parsedDoc","errorDetails","existedInLocalStorage","baseStorageId","bucketName","isValidResponse","responseData","handleFinishedUpload","handleUpload","azure","AZURE_PARAM_PREFIX","_paramNameMatchesAzureParameter","getParamsAsHeaders","parseAzureError","codeTag","messageTag","errorTag","blobProperties","_cannedBlobNames","getBlobName","onGetBlobName","_determineBlobName","deleteBlob","_deleteBlob","blobNameOptionValue","fileExtension","blobNameToUse","blobName","relatedToCancel","deleteBlobSasUri","blobUriStore","deleteFileEndpointStore","getSasSuccess","sasUri","getSasFailure","DeleteBlob","getSas","GetSas","restRequestVerb","combineChunks","getSignedUrl","mimeType","blockIdEntries","putBlockList","determineBlobUrl","containerUrl","getBlobNameSuccess","getBlobNameFailure","getSasId","getSasXhr","determineBlobUrlSuccess","blobUrl","getSasForPutBlobOrBlock","determineBlobUrlFailure","azureError","minFileSizeForChunking","getBlobMetadata","putBlob","PutBlob","putBlock","PutBlock","PutBlockList","blockIdEntry","chunkingData","maybePossible","sasResponseReceived","requestPromises","blobUri","requestPromise","restVerb","bloburi","codes","endpoints","createBlockId","digits","zeros","paddedPartNum","btoa","blockId","createRequestBody","latestEl","latestTextEl","fileMimeType","registerXhrCallback","blockIdsXml","x-ms-blob-content-type"],"mappings":"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","file":"all.fine-uploader.core.min.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\"\"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq*/\n/**\n * Upload handler used that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to\n * a generic server.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.traditional = qq.traditional || {};\nqq.traditional.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log;\n\n /**\n * Returns json object received by iframe from server.\n */\n function getIframeContentJson(id, iframe) {\n /*jshint evil: true*/\n\n var response, doc, innerHtml;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n log(\"converting iframe's innerHTML to JSON\");\n log(\"innerHTML = \" + innerHtml);\n //plain text response may be wrapped in tag\n if (innerHtml && innerHtml.match(/^>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);\n }\n } else if (thatWords.length > 0xffff) {\n // Copy one word at a time\n for (var i = 0; i < thatSigBytes; i += 4) {\n thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];\n }\n } else {\n // Copy all words at once\n thisWords.push.apply(thisWords, thatWords);\n }\n this.sigBytes += thatSigBytes;\n\n // Chainable\n return this;\n },\n\n /**\n * Removes insignificant bits.\n *\n * @example\n *\n * wordArray.clamp();\n */\n clamp: function () {\n // Shortcuts\n var words = this.words;\n var sigBytes = this.sigBytes;\n\n // Clamp\n words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);\n words.length = Math.ceil(sigBytes / 4);\n },\n\n /**\n * Creates a copy of this word array.\n *\n * @return {WordArray} The clone.\n *\n * @example\n *\n * var clone = wordArray.clone();\n */\n clone: function () {\n var clone = Base.clone.call(this);\n clone.words = this.words.slice(0);\n\n return clone;\n },\n\n /**\n * Creates a word array filled with random bytes.\n *\n * @param {number} nBytes The number of random bytes to generate.\n *\n * @return {WordArray} The random word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.lib.WordArray.random(16);\n */\n random: function (nBytes) {\n var words = [];\n for (var i = 0; i < nBytes; i += 4) {\n words.push((Math.random() * 0x100000000) | 0);\n }\n\n return new WordArray.init(words, nBytes);\n }\n });\n\n /**\n * Encoder namespace.\n */\n var C_enc = C.enc = {};\n\n /**\n * Hex encoding strategy.\n */\n var Hex = C_enc.Hex = {\n /**\n * Converts a word array to a hex string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The hex string.\n *\n * @static\n *\n * @example\n *\n * var hexString = CryptoJS.enc.Hex.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n\n // Convert\n var hexChars = [];\n for (var i = 0; i < sigBytes; i++) {\n var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n hexChars.push((bite >>> 4).toString(16));\n hexChars.push((bite & 0x0f).toString(16));\n }\n\n return hexChars.join('');\n },\n\n /**\n * Converts a hex string to a word array.\n *\n * @param {string} hexStr The hex string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Hex.parse(hexString);\n */\n parse: function (hexStr) {\n // Shortcut\n var hexStrLength = hexStr.length;\n\n // Convert\n var words = [];\n for (var i = 0; i < hexStrLength; i += 2) {\n words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);\n }\n\n return new WordArray.init(words, hexStrLength / 2);\n }\n };\n\n /**\n * Latin1 encoding strategy.\n */\n var Latin1 = C_enc.Latin1 = {\n /**\n * Converts a word array to a Latin1 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Latin1 string.\n *\n * @static\n *\n * @example\n *\n * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n\n // Convert\n var latin1Chars = [];\n for (var i = 0; i < sigBytes; i++) {\n var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n latin1Chars.push(String.fromCharCode(bite));\n }\n\n return latin1Chars.join('');\n },\n\n /**\n * Converts a Latin1 string to a word array.\n *\n * @param {string} latin1Str The Latin1 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Latin1.parse(latin1String);\n */\n parse: function (latin1Str) {\n // Shortcut\n var latin1StrLength = latin1Str.length;\n\n // Convert\n var words = [];\n for (var i = 0; i < latin1StrLength; i++) {\n words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);\n }\n\n return new WordArray.init(words, latin1StrLength);\n }\n };\n\n /**\n * UTF-8 encoding strategy.\n */\n var Utf8 = C_enc.Utf8 = {\n /**\n * Converts a word array to a UTF-8 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The UTF-8 string.\n *\n * @static\n *\n * @example\n *\n * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);\n */\n stringify: function (wordArray) {\n try {\n return decodeURIComponent(escape(Latin1.stringify(wordArray)));\n } catch (e) {\n throw new Error('Malformed UTF-8 data');\n }\n },\n\n /**\n * Converts a UTF-8 string to a word array.\n *\n * @param {string} utf8Str The UTF-8 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Utf8.parse(utf8String);\n */\n parse: function (utf8Str) {\n return Latin1.parse(unescape(encodeURIComponent(utf8Str)));\n }\n };\n\n /**\n * Abstract buffered block algorithm template.\n *\n * The property blockSize must be implemented in a concrete subtype.\n *\n * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0\n */\n var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({\n /**\n * Resets this block algorithm's data buffer to its initial state.\n *\n * @example\n *\n * bufferedBlockAlgorithm.reset();\n */\n reset: function () {\n // Initial values\n this._data = new WordArray.init();\n this._nDataBytes = 0;\n },\n\n /**\n * Adds new data to this block algorithm's buffer.\n *\n * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.\n *\n * @example\n *\n * bufferedBlockAlgorithm._append('data');\n * bufferedBlockAlgorithm._append(wordArray);\n */\n _append: function (data) {\n // Convert string to WordArray, else assume WordArray already\n if (typeof data == 'string') {\n data = Utf8.parse(data);\n }\n\n // Append\n this._data.concat(data);\n this._nDataBytes += data.sigBytes;\n },\n\n /**\n * Processes available data blocks.\n *\n * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.\n *\n * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.\n *\n * @return {WordArray} The processed data.\n *\n * @example\n *\n * var processedData = bufferedBlockAlgorithm._process();\n * var processedData = bufferedBlockAlgorithm._process(!!'flush');\n */\n _process: function (doFlush) {\n // Shortcuts\n var data = this._data;\n var dataWords = data.words;\n var dataSigBytes = data.sigBytes;\n var blockSize = this.blockSize;\n var blockSizeBytes = blockSize * 4;\n\n // Count blocks ready\n var nBlocksReady = dataSigBytes / blockSizeBytes;\n if (doFlush) {\n // Round up to include partial blocks\n nBlocksReady = Math.ceil(nBlocksReady);\n } else {\n // Round down to include only full blocks,\n // less the number of blocks that must remain in the buffer\n nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);\n }\n\n // Count words ready\n var nWordsReady = nBlocksReady * blockSize;\n\n // Count bytes ready\n var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);\n\n // Process blocks\n if (nWordsReady) {\n for (var offset = 0; offset < nWordsReady; offset += blockSize) {\n // Perform concrete-algorithm logic\n this._doProcessBlock(dataWords, offset);\n }\n\n // Remove processed words\n var processedWords = dataWords.splice(0, nWordsReady);\n data.sigBytes -= nBytesReady;\n }\n\n // Return processed words\n return new WordArray.init(processedWords, nBytesReady);\n },\n\n /**\n * Creates a copy of this object.\n *\n * @return {Object} The clone.\n *\n * @example\n *\n * var clone = bufferedBlockAlgorithm.clone();\n */\n clone: function () {\n var clone = Base.clone.call(this);\n clone._data = this._data.clone();\n\n return clone;\n },\n\n _minBufferSize: 0\n });\n\n /**\n * Abstract hasher template.\n *\n * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)\n */\n var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({\n /**\n * Configuration options.\n */\n cfg: Base.extend(),\n\n /**\n * Initializes a newly created hasher.\n *\n * @param {Object} cfg (Optional) The configuration options to use for this hash computation.\n *\n * @example\n *\n * var hasher = CryptoJS.algo.SHA256.create();\n */\n init: function (cfg) {\n // Apply config defaults\n this.cfg = this.cfg.extend(cfg);\n\n // Set initial values\n this.reset();\n },\n\n /**\n * Resets this hasher to its initial state.\n *\n * @example\n *\n * hasher.reset();\n */\n reset: function () {\n // Reset data buffer\n BufferedBlockAlgorithm.reset.call(this);\n\n // Perform concrete-hasher logic\n this._doReset();\n },\n\n /**\n * Updates this hasher with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {Hasher} This hasher.\n *\n * @example\n *\n * hasher.update('message');\n * hasher.update(wordArray);\n */\n update: function (messageUpdate) {\n // Append\n this._append(messageUpdate);\n\n // Update the hash\n this._process();\n\n // Chainable\n return this;\n },\n\n /**\n * Finalizes the hash computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The hash.\n *\n * @example\n *\n * var hash = hasher.finalize();\n * var hash = hasher.finalize('message');\n * var hash = hasher.finalize(wordArray);\n */\n finalize: function (messageUpdate) {\n // Final message update\n if (messageUpdate) {\n this._append(messageUpdate);\n }\n\n // Perform concrete-hasher logic\n var hash = this._doFinalize();\n\n return hash;\n },\n\n blockSize: 512/32,\n\n /**\n * Creates a shortcut function to a hasher's object interface.\n *\n * @param {Hasher} hasher The hasher to create a helper for.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);\n */\n _createHelper: function (hasher) {\n return function (message, cfg) {\n return new hasher.init(cfg).finalize(message);\n };\n },\n\n /**\n * Creates a shortcut function to the HMAC's object interface.\n *\n * @param {Hasher} hasher The hasher to use in this HMAC helper.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);\n */\n _createHmacHelper: function (hasher) {\n return function (message, key) {\n return new C_algo.HMAC.init(hasher, key).finalize(message);\n };\n }\n });\n\n /**\n * Algorithm namespace.\n */\n var C_algo = C.algo = {};\n\n return C;\n}(Math));\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var WordArray = C_lib.WordArray;\n var C_enc = C.enc;\n\n /**\n * Base64 encoding strategy.\n */\n var Base64 = C_enc.Base64 = {\n /**\n * Converts a word array to a Base64 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Base64 string.\n *\n * @static\n *\n * @example\n *\n * var base64String = CryptoJS.enc.Base64.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n var map = this._map;\n\n // Clamp excess bits\n wordArray.clamp();\n\n // Convert\n var base64Chars = [];\n for (var i = 0; i < sigBytes; i += 3) {\n var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;\n var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;\n\n var triplet = (byte1 << 16) | (byte2 << 8) | byte3;\n\n for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {\n base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));\n }\n }\n\n // Add padding\n var paddingChar = map.charAt(64);\n if (paddingChar) {\n while (base64Chars.length % 4) {\n base64Chars.push(paddingChar);\n }\n }\n\n return base64Chars.join('');\n },\n\n /**\n * Converts a Base64 string to a word array.\n *\n * @param {string} base64Str The Base64 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Base64.parse(base64String);\n */\n parse: function (base64Str) {\n // Shortcuts\n var base64StrLength = base64Str.length;\n var map = this._map;\n\n // Ignore padding\n var paddingChar = map.charAt(64);\n if (paddingChar) {\n var paddingIndex = base64Str.indexOf(paddingChar);\n if (paddingIndex != -1) {\n base64StrLength = paddingIndex;\n }\n }\n\n // Convert\n var words = [];\n var nBytes = 0;\n for (var i = 0; i < base64StrLength; i++) {\n if (i % 4) {\n var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2);\n var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2);\n words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8);\n nBytes++;\n }\n }\n\n return WordArray.create(words, nBytes);\n },\n\n _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='\n };\n}());\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var Base = C_lib.Base;\n var C_enc = C.enc;\n var Utf8 = C_enc.Utf8;\n var C_algo = C.algo;\n\n /**\n * HMAC algorithm.\n */\n var HMAC = C_algo.HMAC = Base.extend({\n /**\n * Initializes a newly created HMAC.\n *\n * @param {Hasher} hasher The hash algorithm to use.\n * @param {WordArray|string} key The secret key.\n *\n * @example\n *\n * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);\n */\n init: function (hasher, key) {\n // Init hasher\n hasher = this._hasher = new hasher.init();\n\n // Convert string to WordArray, else assume WordArray already\n if (typeof key == 'string') {\n key = Utf8.parse(key);\n }\n\n // Shortcuts\n var hasherBlockSize = hasher.blockSize;\n var hasherBlockSizeBytes = hasherBlockSize * 4;\n\n // Allow arbitrary length keys\n if (key.sigBytes > hasherBlockSizeBytes) {\n key = hasher.finalize(key);\n }\n\n // Clamp excess bits\n key.clamp();\n\n // Clone key for inner and outer pads\n var oKey = this._oKey = key.clone();\n var iKey = this._iKey = key.clone();\n\n // Shortcuts\n var oKeyWords = oKey.words;\n var iKeyWords = iKey.words;\n\n // XOR keys with pad constants\n for (var i = 0; i < hasherBlockSize; i++) {\n oKeyWords[i] ^= 0x5c5c5c5c;\n iKeyWords[i] ^= 0x36363636;\n }\n oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;\n\n // Set initial values\n this.reset();\n },\n\n /**\n * Resets this HMAC to its initial state.\n *\n * @example\n *\n * hmacHasher.reset();\n */\n reset: function () {\n // Shortcut\n var hasher = this._hasher;\n\n // Reset\n hasher.reset();\n hasher.update(this._iKey);\n },\n\n /**\n * Updates this HMAC with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {HMAC} This HMAC instance.\n *\n * @example\n *\n * hmacHasher.update('message');\n * hmacHasher.update(wordArray);\n */\n update: function (messageUpdate) {\n this._hasher.update(messageUpdate);\n\n // Chainable\n return this;\n },\n\n /**\n * Finalizes the HMAC computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The HMAC.\n *\n * @example\n *\n * var hmac = hmacHasher.finalize();\n * var hmac = hmacHasher.finalize('message');\n * var hmac = hmacHasher.finalize(wordArray);\n */\n finalize: function (messageUpdate) {\n // Shortcut\n var hasher = this._hasher;\n\n // Compute HMAC\n var innerHash = hasher.finalize(messageUpdate);\n hasher.reset();\n var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));\n\n return hmac;\n }\n });\n}());\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var WordArray = C_lib.WordArray;\n var Hasher = C_lib.Hasher;\n var C_algo = C.algo;\n\n // Reusable object\n var W = [];\n\n /**\n * SHA-1 hash algorithm.\n */\n var SHA1 = C_algo.SHA1 = Hasher.extend({\n _doReset: function () {\n this._hash = new WordArray.init([\n 0x67452301, 0xefcdab89,\n 0x98badcfe, 0x10325476,\n 0xc3d2e1f0\n ]);\n },\n\n _doProcessBlock: function (M, offset) {\n // Shortcut\n var H = this._hash.words;\n\n // Working variables\n var a = H[0];\n var b = H[1];\n var c = H[2];\n var d = H[3];\n var e = H[4];\n\n // Computation\n for (var i = 0; i < 80; i++) {\n if (i < 16) {\n W[i] = M[offset + i] | 0;\n } else {\n var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];\n W[i] = (n << 1) | (n >>> 31);\n }\n\n var t = ((a << 5) | (a >>> 27)) + e + W[i];\n if (i < 20) {\n t += ((b & c) | (~b & d)) + 0x5a827999;\n } else if (i < 40) {\n t += (b ^ c ^ d) + 0x6ed9eba1;\n } else if (i < 60) {\n t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;\n } else /* if (i < 80) */ {\n t += (b ^ c ^ d) - 0x359d3e2a;\n }\n\n e = d;\n d = c;\n c = (b << 30) | (b >>> 2);\n b = a;\n a = t;\n }\n\n // Intermediate hash value\n H[0] = (H[0] + a) | 0;\n H[1] = (H[1] + b) | 0;\n H[2] = (H[2] + c) | 0;\n H[3] = (H[3] + d) | 0;\n H[4] = (H[4] + e) | 0;\n },\n\n _doFinalize: function () {\n // Shortcuts\n var data = this._data;\n var dataWords = data.words;\n\n var nBitsTotal = this._nDataBytes * 8;\n var nBitsLeft = data.sigBytes * 8;\n\n // Add padding\n dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\n data.sigBytes = dataWords.length * 4;\n\n // Hash final blocks\n this._process();\n\n // Return final computed hash\n return this._hash;\n },\n\n clone: function () {\n var clone = Hasher.clone.call(this);\n clone._hash = this._hash.clone();\n\n return clone;\n }\n });\n\n /**\n * Shortcut function to the hasher's object interface.\n *\n * @param {WordArray|string} message The message to hash.\n *\n * @return {WordArray} The hash.\n *\n * @static\n *\n * @example\n *\n * var hash = CryptoJS.SHA1('message');\n * var hash = CryptoJS.SHA1(wordArray);\n */\n C.SHA1 = Hasher._createHelper(SHA1);\n\n /**\n * Shortcut function to the HMAC's object interface.\n *\n * @param {WordArray|string} message The message to hash.\n * @param {WordArray|string} key The secret key.\n *\n * @return {WordArray} The HMAC.\n *\n * @static\n *\n * @example\n *\n * var hmac = CryptoJS.HmacSHA1(message, key);\n */\n C.HmacSHA1 = Hasher._createHmacHelper(SHA1);\n}());\n","/*\r\nCryptoJS v3.1.2\r\ncode.google.com/p/crypto-js\r\n(c) 2009-2013 by Jeff Mott. All rights reserved.\r\ncode.google.com/p/crypto-js/wiki/License\r\n*/\r\n(function (Math) {\r\n // Shortcuts\r\n var C = qq.CryptoJS;\r\n var C_lib = C.lib;\r\n var WordArray = C_lib.WordArray;\r\n var Hasher = C_lib.Hasher;\r\n var C_algo = C.algo;\r\n\r\n // Initialization and round constants tables\r\n var H = [];\r\n var K = [];\r\n\r\n // Compute constants\r\n (function () {\r\n function isPrime(n) {\r\n var sqrtN = Math.sqrt(n);\r\n for (var factor = 2; factor <= sqrtN; factor++) {\r\n if (!(n % factor)) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n function getFractionalBits(n) {\r\n return ((n - (n | 0)) * 0x100000000) | 0;\r\n }\r\n\r\n var n = 2;\r\n var nPrime = 0;\r\n while (nPrime < 64) {\r\n if (isPrime(n)) {\r\n if (nPrime < 8) {\r\n H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));\r\n }\r\n K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));\r\n\r\n nPrime++;\r\n }\r\n\r\n n++;\r\n }\r\n }());\r\n\r\n // Reusable object\r\n var W = [];\r\n\r\n /**\r\n * SHA-256 hash algorithm.\r\n */\r\n var SHA256 = C_algo.SHA256 = Hasher.extend({\r\n _doReset: function () {\r\n this._hash = new WordArray.init(H.slice(0));\r\n },\r\n\r\n _doProcessBlock: function (M, offset) {\r\n // Shortcut\r\n var H = this._hash.words;\r\n\r\n // Working variables\r\n var a = H[0];\r\n var b = H[1];\r\n var c = H[2];\r\n var d = H[3];\r\n var e = H[4];\r\n var f = H[5];\r\n var g = H[6];\r\n var h = H[7];\r\n\r\n // Computation\r\n for (var i = 0; i < 64; i++) {\r\n if (i < 16) {\r\n W[i] = M[offset + i] | 0;\r\n } else {\r\n var gamma0x = W[i - 15];\r\n var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^\r\n ((gamma0x << 14) | (gamma0x >>> 18)) ^\r\n (gamma0x >>> 3);\r\n\r\n var gamma1x = W[i - 2];\r\n var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^\r\n ((gamma1x << 13) | (gamma1x >>> 19)) ^\r\n (gamma1x >>> 10);\r\n\r\n W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];\r\n }\r\n\r\n var ch = (e & f) ^ (~e & g);\r\n var maj = (a & b) ^ (a & c) ^ (b & c);\r\n\r\n var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));\r\n var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25));\r\n\r\n var t1 = h + sigma1 + ch + K[i] + W[i];\r\n var t2 = sigma0 + maj;\r\n\r\n h = g;\r\n g = f;\r\n f = e;\r\n e = (d + t1) | 0;\r\n d = c;\r\n c = b;\r\n b = a;\r\n a = (t1 + t2) | 0;\r\n }\r\n\r\n // Intermediate hash value\r\n H[0] = (H[0] + a) | 0;\r\n H[1] = (H[1] + b) | 0;\r\n H[2] = (H[2] + c) | 0;\r\n H[3] = (H[3] + d) | 0;\r\n H[4] = (H[4] + e) | 0;\r\n H[5] = (H[5] + f) | 0;\r\n H[6] = (H[6] + g) | 0;\r\n H[7] = (H[7] + h) | 0;\r\n },\r\n\r\n _doFinalize: function () {\r\n // Shortcuts\r\n var data = this._data;\r\n var dataWords = data.words;\r\n\r\n var nBitsTotal = this._nDataBytes * 8;\r\n var nBitsLeft = data.sigBytes * 8;\r\n\r\n // Add padding\r\n dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\r\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\r\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\r\n data.sigBytes = dataWords.length * 4;\r\n\r\n // Hash final blocks\r\n this._process();\r\n\r\n // Return final computed hash\r\n return this._hash;\r\n },\r\n\r\n clone: function () {\r\n var clone = Hasher.clone.call(this);\r\n clone._hash = this._hash.clone();\r\n\r\n return clone;\r\n }\r\n });\r\n\r\n /**\r\n * Shortcut function to the hasher's object interface.\r\n *\r\n * @param {WordArray|string} message The message to hash.\r\n *\r\n * @return {WordArray} The hash.\r\n *\r\n * @static\r\n *\r\n * @example\r\n *\r\n * var hash = CryptoJS.SHA256('message');\r\n * var hash = CryptoJS.SHA256(wordArray);\r\n */\r\n C.SHA256 = Hasher._createHelper(SHA256);\r\n\r\n /**\r\n * Shortcut function to the HMAC's object interface.\r\n *\r\n * @param {WordArray|string} message The message to hash.\r\n * @param {WordArray|string} key The secret key.\r\n *\r\n * @return {WordArray} The HMAC.\r\n *\r\n * @static\r\n *\r\n * @example\r\n *\r\n * var hmac = CryptoJS.HmacSHA256(message, key);\r\n */\r\n C.HmacSHA256 = Hasher._createHmacHelper(SHA256);\r\n}(Math));\r\n","/*\r\nCryptoJS v3.1.2\r\ncode.google.com/p/crypto-js\r\n(c) 2009-2013 by Jeff Mott. All rights reserved.\r\ncode.google.com/p/crypto-js/wiki/License\r\n*/\r\n(function () {\r\n // Check if typed arrays are supported\r\n if (typeof ArrayBuffer != 'function') {\r\n return;\r\n }\r\n\r\n // Shortcuts\r\n var C = qq.CryptoJS;\r\n var C_lib = C.lib;\r\n var WordArray = C_lib.WordArray;\r\n\r\n // Reference original init\r\n var superInit = WordArray.init;\r\n\r\n // Augment WordArray.init to handle typed arrays\r\n var subInit = WordArray.init = function (typedArray) {\r\n // Convert buffers to uint8\r\n if (typedArray instanceof ArrayBuffer) {\r\n typedArray = new Uint8Array(typedArray);\r\n }\r\n\r\n // Convert other array views to uint8\r\n if (\r\n typedArray instanceof Int8Array ||\r\n typedArray instanceof Uint8ClampedArray ||\r\n typedArray instanceof Int16Array ||\r\n typedArray instanceof Uint16Array ||\r\n typedArray instanceof Int32Array ||\r\n typedArray instanceof Uint32Array ||\r\n typedArray instanceof Float32Array ||\r\n typedArray instanceof Float64Array\r\n ) {\r\n typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);\r\n }\r\n\r\n // Handle Uint8Array\r\n if (typedArray instanceof Uint8Array) {\r\n // Shortcut\r\n var typedArrayByteLength = typedArray.byteLength;\r\n\r\n // Extract bytes\r\n var words = [];\r\n for (var i = 0; i < typedArrayByteLength; i++) {\r\n words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8);\r\n }\r\n\r\n // Initialize this word array\r\n superInit.call(this, words, typedArrayByteLength);\r\n } else {\r\n // Else call normal init\r\n superInit.apply(this, arguments);\r\n }\r\n };\r\n\r\n subInit.prototype = WordArray;\r\n}());\r\n","/*globals qq */\nqq.s3 = qq.s3 || {};\n\nqq.s3.util = qq.s3.util || (function() {\n \"use strict\";\n\n return {\n ALGORITHM_PARAM_NAME: \"x-amz-algorithm\",\n\n AWS_PARAM_PREFIX: \"x-amz-meta-\",\n\n CREDENTIAL_PARAM_NAME: \"x-amz-credential\",\n\n DATE_PARAM_NAME: \"x-amz-date\",\n\n REDUCED_REDUNDANCY_PARAM_NAME: \"x-amz-storage-class\",\n REDUCED_REDUNDANCY_PARAM_VALUE: \"REDUCED_REDUNDANCY\",\n\n SERVER_SIDE_ENCRYPTION_PARAM_NAME: \"x-amz-server-side-encryption\",\n SERVER_SIDE_ENCRYPTION_PARAM_VALUE: \"AES256\",\n\n SESSION_TOKEN_PARAM_NAME: \"x-amz-security-token\",\n\n V4_ALGORITHM_PARAM_VALUE: \"AWS4-HMAC-SHA256\",\n\n V4_SIGNATURE_PARAM_NAME: \"x-amz-signature\",\n\n CASE_SENSITIVE_PARAM_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\"\n ],\n\n UNSIGNABLE_REST_HEADER_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\"\n ],\n\n UNPREFIXED_PARAM_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\",\n \"x-amz-server-side-encryption-customer-algorithm\",\n \"x-amz-server-side-encryption-customer-key\",\n \"x-amz-server-side-encryption-customer-key-MD5\"\n ],\n\n /**\n * This allows for the region to be specified in the bucket's endpoint URL, or not.\n *\n * Examples of some valid endpoints are:\n * http://foo.s3.amazonaws.com\n * https://foo.s3.amazonaws.com\n * http://foo.s3-ap-northeast-1.amazonaws.com\n * foo.s3.amazonaws.com\n * http://foo.bar.com\n * http://s3.amazonaws.com/foo.bar.com\n * ...etc\n *\n * @param endpoint The bucket's URL.\n * @returns {String || undefined} The bucket name, or undefined if the URL cannot be parsed.\n */\n getBucket: function(endpoint) {\n var patterns = [\n //bucket in domain\n /^(?:https?:\\/\\/)?([a-z0-9.\\-_]+)\\.s3(?:-[a-z0-9\\-]+)?\\.amazonaws\\.com/i,\n //bucket in path\n /^(?:https?:\\/\\/)?s3(?:-[a-z0-9\\-]+)?\\.amazonaws\\.com\\/([a-z0-9.\\-_]+)/i,\n //custom domain\n /^(?:https?:\\/\\/)?([a-z0-9.\\-_]+)/i\n ],\n bucket;\n\n qq.each(patterns, function(idx, pattern) {\n var match = pattern.exec(endpoint);\n\n if (match) {\n bucket = match[1];\n return false;\n }\n });\n\n return bucket;\n },\n\n /** Create Prefixed request headers which are appropriate for S3.\n *\n * If the request header is appropriate for S3 (e.g. Cache-Control) then pass\n * it along without a metadata prefix. For all other request header parameter names,\n * apply qq.s3.util.AWS_PARAM_PREFIX before the name.\n * See: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html\n */\n _getPrefixedParamName: function(name) {\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {\n return name;\n }\n return qq.s3.util.AWS_PARAM_PREFIX + name;\n },\n\n /**\n * Create a policy document to be signed and sent along with the S3 upload request.\n *\n * @param spec Object with properties use to construct the policy document.\n * @returns {Object} Policy doc.\n */\n getPolicy: function(spec) {\n var policy = {},\n conditions = [],\n bucket = spec.bucket,\n date = spec.date,\n drift = spec.clockDrift,\n key = spec.key,\n accessKey = spec.accessKey,\n acl = spec.acl,\n type = spec.type,\n expectedStatus = spec.expectedStatus,\n sessionToken = spec.sessionToken,\n params = spec.params,\n successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl),\n minFileSize = spec.minFileSize,\n maxFileSize = spec.maxFileSize,\n reducedRedundancy = spec.reducedRedundancy,\n region = spec.region,\n serverSideEncryption = spec.serverSideEncryption,\n signatureVersion = spec.signatureVersion;\n\n policy.expiration = qq.s3.util.getPolicyExpirationDate(date, drift);\n\n conditions.push({acl: acl});\n conditions.push({bucket: bucket});\n\n if (type) {\n conditions.push({\"Content-Type\": type});\n }\n\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (expectedStatus) {\n conditions.push({success_action_status: expectedStatus.toString()});\n }\n\n if (successRedirectUrl) {\n conditions.push({success_action_redirect: successRedirectUrl});\n }\n // jscs:enable\n if (reducedRedundancy) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (sessionToken) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n if (serverSideEncryption) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n if (signatureVersion === 2) {\n conditions.push({key: key});\n }\n else if (signatureVersion === 4) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;\n\n conditions.push({});\n conditions[conditions.length - 1].key = key;\n\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.CREDENTIAL_PARAM_NAME] =\n qq.s3.util.getV4CredentialsString({date: date, key: accessKey, region: region});\n\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.DATE_PARAM_NAME] =\n qq.s3.util.getV4PolicyDate(date, drift);\n }\n\n // user metadata\n qq.each(params, function(name, val) {\n var awsParamName = qq.s3.util._getPrefixedParamName(name),\n param = {};\n\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {\n param[awsParamName] = val;\n }\n else {\n param[awsParamName] = encodeURIComponent(val);\n }\n\n conditions.push(param);\n });\n\n policy.conditions = conditions;\n\n qq.s3.util.enforceSizeLimits(policy, minFileSize, maxFileSize);\n\n return policy;\n },\n\n /**\n * Update a previously constructed policy document with updated credentials. Currently, this only requires we\n * update the session token. This is only relevant if requests are being signed client-side.\n *\n * @param policy Live policy document\n * @param newSessionToken Updated session token.\n */\n refreshPolicyCredentials: function(policy, newSessionToken) {\n var sessionTokenFound = false;\n\n qq.each(policy.conditions, function(oldCondIdx, oldCondObj) {\n qq.each(oldCondObj, function(oldCondName, oldCondVal) {\n if (oldCondName === qq.s3.util.SESSION_TOKEN_PARAM_NAME) {\n oldCondObj[oldCondName] = newSessionToken;\n sessionTokenFound = true;\n }\n });\n });\n\n if (!sessionTokenFound) {\n policy.conditions.push({});\n policy.conditions[policy.conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = newSessionToken;\n }\n },\n\n /**\n * Generates all parameters to be passed along with the S3 upload request. This includes invoking a callback\n * that is expected to asynchronously retrieve a signature for the policy document. Note that the server\n * signing the request should reject a \"tainted\" policy document that includes unexpected values, since it is\n * still possible for a malicious user to tamper with these values during policy document generation,\n * before it is sent to the server for signing.\n *\n * @param spec Object with properties: `params`, `type`, `key`, `accessKey`, `acl`, `expectedStatus`, `successRedirectUrl`,\n * `reducedRedundancy`, `region`, `serverSideEncryption`, `version`, and `log()`, along with any options associated with `qq.s3.util.getPolicy()`.\n * @returns {qq.Promise} Promise that will be fulfilled once all parameters have been determined.\n */\n generateAwsParams: function(spec, signPolicyCallback) {\n var awsParams = {},\n customParams = spec.params,\n promise = new qq.Promise(),\n sessionToken = spec.sessionToken,\n drift = spec.clockDrift,\n type = spec.type,\n key = spec.key,\n accessKey = spec.accessKey,\n acl = spec.acl,\n expectedStatus = spec.expectedStatus,\n successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl),\n reducedRedundancy = spec.reducedRedundancy,\n region = spec.region,\n serverSideEncryption = spec.serverSideEncryption,\n signatureVersion = spec.signatureVersion,\n now = new Date(),\n log = spec.log,\n policyJson;\n\n spec.date = now;\n policyJson = qq.s3.util.getPolicy(spec);\n\n awsParams.key = key;\n\n if (type) {\n awsParams[\"Content-Type\"] = type;\n }\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (expectedStatus) {\n awsParams.success_action_status = expectedStatus;\n }\n\n if (successRedirectUrl) {\n awsParams.success_action_redirect = successRedirectUrl;\n }\n // jscs:enable\n if (reducedRedundancy) {\n awsParams[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (serverSideEncryption) {\n awsParams[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n if (sessionToken) {\n awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n awsParams.acl = acl;\n\n // Custom (user-supplied) params must be prefixed with the value of `qq.s3.util.AWS_PARAM_PREFIX`.\n // Params such as Cache-Control or Content-Disposition will not be prefixed.\n // Prefixed param values will be URI encoded as well.\n qq.each(customParams, function(name, val) {\n var awsParamName = qq.s3.util._getPrefixedParamName(name);\n\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {\n awsParams[awsParamName] = val;\n }\n else {\n awsParams[awsParamName] = encodeURIComponent(val);\n }\n });\n\n if (signatureVersion === 2) {\n awsParams.AWSAccessKeyId = accessKey;\n }\n else if (signatureVersion === 4) {\n awsParams[qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;\n awsParams[qq.s3.util.CREDENTIAL_PARAM_NAME] = qq.s3.util.getV4CredentialsString({date: now, key: accessKey, region: region});\n awsParams[qq.s3.util.DATE_PARAM_NAME] = qq.s3.util.getV4PolicyDate(now, drift);\n }\n\n // Invoke a promissory callback that should provide us with a base64-encoded policy doc and an\n // HMAC signature for the policy doc.\n signPolicyCallback(policyJson).then(\n function(policyAndSignature, updatedAccessKey, updatedSessionToken) {\n awsParams.policy = policyAndSignature.policy;\n\n if (spec.signatureVersion === 2) {\n awsParams.signature = policyAndSignature.signature;\n\n if (updatedAccessKey) {\n awsParams.AWSAccessKeyId = updatedAccessKey;\n }\n }\n else if (spec.signatureVersion === 4) {\n awsParams[qq.s3.util.V4_SIGNATURE_PARAM_NAME] = policyAndSignature.signature;\n }\n\n if (updatedSessionToken) {\n awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;\n }\n\n promise.success(awsParams);\n },\n function(errorMessage) {\n errorMessage = errorMessage || \"Can't continue further with request to S3 as we did not receive \" +\n \"a valid signature and policy from the server.\";\n\n log(\"Policy signing failed. \" + errorMessage, \"error\");\n promise.failure(errorMessage);\n }\n );\n\n return promise;\n },\n\n /**\n * Add a condition to an existing S3 upload request policy document used to ensure AWS enforces any size\n * restrictions placed on files server-side. This is important to do, in case users mess with the client-side\n * checks already in place.\n *\n * @param policy Policy document as an `Object`, with a `conditions` property already attached\n * @param minSize Minimum acceptable size, in bytes\n * @param maxSize Maximum acceptable size, in bytes (0 = unlimited)\n */\n enforceSizeLimits: function(policy, minSize, maxSize) {\n var adjustedMinSize = minSize < 0 ? 0 : minSize,\n // Adjust a maxSize of 0 to the largest possible integer, since we must specify a high and a low in the request\n adjustedMaxSize = maxSize <= 0 ? 9007199254740992 : maxSize;\n\n if (minSize > 0 || maxSize > 0) {\n policy.conditions.push([\"content-length-range\", adjustedMinSize.toString(), adjustedMaxSize.toString()]);\n }\n },\n\n getPolicyExpirationDate: function(date, drift) {\n var adjustedDate = new Date(date.getTime() + drift);\n return qq.s3.util.getPolicyDate(adjustedDate, 5);\n },\n\n getCredentialsDate: function(date) {\n return date.getUTCFullYear() + \"\" +\n (\"0\" + (date.getUTCMonth() + 1)).slice(-2) +\n (\"0\" + date.getUTCDate()).slice(-2);\n },\n\n getPolicyDate: function(date, _minutesToAdd_) {\n var minutesToAdd = _minutesToAdd_ || 0,\n pad, r;\n\n /*jshint -W014 */\n // Is this going to be a problem if we encounter this moments before 2 AM just before daylight savings time ends?\n date.setMinutes(date.getMinutes() + (minutesToAdd || 0));\n\n if (Date.prototype.toISOString) {\n return date.toISOString();\n }\n else {\n pad = function(number) {\n r = String(number);\n\n if (r.length === 1) {\n r = \"0\" + r;\n }\n\n return r;\n };\n\n return date.getUTCFullYear()\n + \"-\" + pad(date.getUTCMonth() + 1)\n + \"-\" + pad(date.getUTCDate())\n + \"T\" + pad(date.getUTCHours())\n + \":\" + pad(date.getUTCMinutes())\n + \":\" + pad(date.getUTCSeconds())\n + \".\" + String((date.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)\n + \"Z\";\n }\n },\n\n /**\n * Looks at a response from S3 contained in an iframe and parses the query string in an attempt to identify\n * the associated resource.\n *\n * @param iframe Iframe containing response\n * @returns {{bucket: *, key: *, etag: *}}\n */\n parseIframeResponse: function(iframe) {\n var doc = iframe.contentDocument || iframe.contentWindow.document,\n queryString = doc.location.search,\n match = /bucket=(.+)&key=(.+)&etag=(.+)/.exec(queryString);\n\n if (match) {\n return {\n bucket: match[1],\n key: match[2],\n etag: match[3].replace(/%22/g, \"\")\n };\n }\n },\n\n /**\n * @param successRedirectUrl Relative or absolute location of success redirect page\n * @returns {*|string} undefined if the parameter is undefined, otherwise the absolute location of the success redirect page\n */\n getSuccessRedirectAbsoluteUrl: function(successRedirectUrl) {\n if (successRedirectUrl) {\n var targetAnchorContainer = document.createElement(\"div\"),\n targetAnchor;\n\n if (qq.ie7()) {\n // Note that we must make use of `innerHTML` for IE7 only instead of simply creating an anchor via\n // `document.createElement('a')` and setting the `href` attribute. The latter approach does not allow us to\n // obtain an absolute URL in IE7 if the `endpoint` is a relative URL.\n targetAnchorContainer.innerHTML = \" \";\n targetAnchor = targetAnchorContainer.firstChild;\n return targetAnchor.href;\n }\n else {\n // IE8 and IE9 do not seem to derive an absolute URL from a relative URL using the `innerHTML`\n // approach above, so we'll just create an anchor this way and set it's `href` attribute.\n // Due to yet another quirk in IE8 and IE9, we have to set the `href` equal to itself\n // in order to ensure relative URLs will be properly parsed.\n targetAnchor = document.createElement(\"a\");\n targetAnchor.href = successRedirectUrl;\n targetAnchor.href = targetAnchor.href;\n return targetAnchor.href;\n }\n }\n },\n\n getV4CredentialsString: function(spec) {\n return spec.key + \"/\" +\n qq.s3.util.getCredentialsDate(spec.date) + \"/\" +\n spec.region + \"/s3/aws4_request\";\n },\n\n getV4PolicyDate: function(date, drift) {\n var adjustedDate = new Date(date.getTime() + drift);\n\n return qq.s3.util.getCredentialsDate(adjustedDate) + \"T\" +\n (\"0\" + adjustedDate.getUTCHours()).slice(-2) +\n (\"0\" + adjustedDate.getUTCMinutes()).slice(-2) +\n (\"0\" + adjustedDate.getUTCSeconds()).slice(-2) +\n \"Z\";\n },\n\n // AWS employs a strict interpretation of [RFC 3986](http://tools.ietf.org/html/rfc3986#page-12).\n // So, we must ensure all reserved characters listed in the spec are percent-encoded,\n // and spaces are replaced with \"+\".\n encodeQueryStringParam: function(param) {\n var percentEncoded = encodeURIComponent(param);\n\n // %-encode characters not handled by `encodeURIComponent` (to follow RFC 3986)\n percentEncoded = percentEncoded.replace(/[!'()]/g, escape);\n\n // %-encode characters not handled by `escape` (to follow RFC 3986)\n percentEncoded = percentEncoded.replace(/\\*/g, \"%2A\");\n\n // replace percent-encoded spaces with a \"+\"\n return percentEncoded.replace(/%20/g, \"+\");\n },\n /**\n * Escapes url part as for AWS requirements\n * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js\n */\n uriEscape: function(string) {\n var output = encodeURIComponent(string);\n output = output.replace(/[^A-Za-z0-9_.~\\-%]+/g, escape);\n output = output.replace(/[*]/g, function(ch) {\n return \"%\" + ch.charCodeAt(0).toString(16).toUpperCase();\n });\n return output;\n },\n /**\n * Escapes a path as for AWS requirement\n * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js\n */\n uriEscapePath: function(path) {\n var parts = [];\n qq.each(path.split(\"/\"), function(idx, item) {\n parts.push(qq.s3.util.uriEscape(item));\n });\n return parts.join(\"/\");\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to S3, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to S3.\n * Some inherited options and API methods have a special meaning in the context of the S3 uploader.\n */\n(function() {\n \"use strict\";\n\n qq.s3.FineUploaderBasic = function(o) {\n var options = {\n request: {\n // public key (required for server-side signing, ignored if `credentials` have been provided)\n accessKey: null,\n\n // padding, in milliseconds, to add to the x-amz-date header & the policy expiration date\n clockDrift: 0\n },\n\n objectProperties: {\n acl: \"private\",\n\n // string or a function which may be promissory\n bucket: qq.bind(function(id) {\n return qq.s3.util.getBucket(this.getEndpoint(id));\n }, this),\n\n // string or a function which may be promissory - only used for V4 multipart uploads\n host: qq.bind(function(id) {\n return (/(?:http|https):\\/\\/(.+)(?:\\/.+)?/).exec(this._endpointStore.get(id))[1];\n }, this),\n\n // 'uuid', 'filename', or a function which may be promissory\n key: \"uuid\",\n\n reducedRedundancy: false,\n\n // Defined at http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\n region: \"us-east-1\",\n\n serverSideEncryption: false\n },\n\n credentials: {\n // Public key (required).\n accessKey: null,\n // Private key (required).\n secretKey: null,\n // Expiration date for the credentials (required). May be an ISO string or a `Date`.\n expiration: null,\n // Temporary credentials session token.\n // Only required for temporary credentials obtained via AssumeRoleWithWebIdentity.\n sessionToken: null\n },\n\n // All but `version` are ignored if `credentials` is provided.\n signature: {\n customHeaders: {},\n endpoint: null,\n version: 2\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n // required if non-File-API browsers, such as IE9 and older, are used\n iframeSupport: {\n localBlankPagePath: null\n },\n\n chunking: {\n // minimum part size is 5 MiB when uploading to S3\n partSize: 5242880\n },\n\n cors: {\n allowXdr: true\n },\n\n callbacks: {\n onCredentialsExpired: function() {}\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n if (!this.setCredentials(options.credentials, true)) {\n this._currentCredentials.accessKey = options.request.accessKey;\n }\n\n this._aclStore = this._createStore(options.objectProperties.acl);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds S3 keys for file representations constructed from a session request.\n this._cannedKeys = {};\n // Holds S3 buckets for file representations constructed from a session request.\n this._cannedBuckets = {};\n\n this._buckets = {};\n this._hosts = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.s3.FineUploaderBasic.prototype, {\n getBucket: function(id) {\n if (this._cannedBuckets[id] == null) {\n return this._buckets[id];\n }\n return this._cannedBuckets[id];\n },\n\n /**\n * @param id File ID\n * @returns {*} Key name associated w/ the file, if one exists\n */\n getKey: function(id) {\n /* jshint eqnull:true */\n if (this._cannedKeys[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n\n return this._cannedKeys[id];\n },\n\n /**\n * Override the parent's reset function to cleanup various S3-related items.\n */\n reset: function() {\n qq.FineUploaderBasic.prototype.reset.call(this);\n this._failedSuccessRequestCallbacks = [];\n this._buckets = {};\n this._hosts = {};\n },\n\n setCredentials: function(credentials, ignoreEmpty) {\n if (credentials && credentials.secretKey) {\n if (!credentials.accessKey) {\n throw new qq.Error(\"Invalid credentials: no accessKey\");\n }\n else if (!credentials.expiration) {\n throw new qq.Error(\"Invalid credentials: no expiration\");\n }\n else {\n this._currentCredentials = qq.extend({}, credentials);\n\n // Ensure expiration is a `Date`. If initially a string, assuming it is in ISO format.\n if (qq.isString(credentials.expiration)) {\n this._currentCredentials.expiration = new Date(credentials.expiration);\n }\n }\n\n return true;\n }\n else if (!ignoreEmpty) {\n throw new qq.Error(\"Invalid credentials parameter!\");\n }\n else {\n this._currentCredentials = {};\n }\n },\n\n setAcl: function(acl, id) {\n this._aclStore.set(acl, id);\n },\n\n /**\n * Ensures the parent's upload handler creator passes any additional S3-specific options to the handler as well\n * as information required to instantiate the specific handler based on the current browser's capabilities.\n *\n * @returns {qq.UploadHandlerController}\n * @private\n */\n _createUploadHandler: function() {\n var self = this,\n additionalOptions = {\n aclStore: this._aclStore,\n getBucket: qq.bind(this._determineBucket, this),\n getHost: qq.bind(this._determineHost, this),\n getKeyName: qq.bind(this._determineKeyName, this),\n iframeSupport: this._options.iframeSupport,\n objectProperties: this._options.objectProperties,\n signature: this._options.signature,\n clockDrift: this._options.request.clockDrift,\n // pass size limit validation values to include in the request so AWS enforces this server-side\n validation: {\n minSizeLimit: this._options.validation.minSizeLimit,\n maxSizeLimit: this._options.validation.sizeLimit\n }\n };\n\n // We assume HTTP if it is missing from the start of the endpoint string.\n qq.override(this._endpointStore, function(super_) {\n return {\n get: function(id) {\n var endpoint = super_.get(id);\n\n if (endpoint.indexOf(\"http\") < 0) {\n return \"http://\" + endpoint;\n }\n\n return endpoint;\n }\n };\n });\n\n // Some param names should be lower case to avoid signature mismatches\n qq.override(this._paramsStore, function(super_) {\n return {\n get: function(id) {\n var oldParams = super_.get(id),\n modifiedParams = {};\n\n qq.each(oldParams, function(name, val) {\n var paramName = name;\n\n if (qq.indexOf(qq.s3.util.CASE_SENSITIVE_PARAM_NAMES, paramName) < 0) {\n paramName = paramName.toLowerCase();\n }\n\n modifiedParams[paramName] = qq.isFunction(val) ? val() : val;\n });\n\n return modifiedParams;\n }\n };\n });\n\n additionalOptions.signature.credentialsProvider = {\n get: function() {\n return self._currentCredentials;\n },\n\n onExpired: function() {\n var updateCredentials = new qq.Promise(),\n callbackRetVal = self._options.callbacks.onCredentialsExpired();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n callbackRetVal.then(function(credentials) {\n try {\n self.setCredentials(credentials);\n updateCredentials.success();\n }\n catch (error) {\n self.log(\"Invalid credentials returned from onCredentialsExpired callback! (\" + error.message + \")\", \"error\");\n updateCredentials.failure(\"onCredentialsExpired did not return valid credentials.\");\n }\n }, function(errorMsg) {\n self.log(\"onCredentialsExpired callback indicated failure! (\" + errorMsg + \")\", \"error\");\n updateCredentials.failure(\"onCredentialsExpired callback failed.\");\n });\n }\n else {\n self.log(\"onCredentialsExpired callback did not return a promise!\", \"error\");\n updateCredentials.failure(\"Unexpected return value for onCredentialsExpired.\");\n }\n\n return updateCredentials;\n }\n };\n\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this, additionalOptions, \"s3\");\n },\n\n _determineObjectPropertyValue: function(id, property) {\n var maybe = this._options.objectProperties[property],\n promise = new qq.Promise(),\n self = this;\n\n if (qq.isFunction(maybe)) {\n maybe = maybe(id);\n if (qq.isGenericPromise(maybe)) {\n promise = maybe;\n }\n else {\n promise.success(maybe);\n }\n }\n else if (qq.isString(maybe)) {\n promise.success(maybe);\n }\n\n promise.then(\n function success(value) {\n self[\"_\" + property + \"s\"][id] = value;\n },\n\n function failure(errorMsg) {\n qq.log(\"Problem determining \" + property + \" for ID \" + id + \" (\" + errorMsg + \")\", \"error\");\n }\n );\n\n return promise;\n },\n\n _determineBucket: function(id) {\n return this._determineObjectPropertyValue(id, \"bucket\");\n },\n\n _determineHost: function(id) {\n return this._determineObjectPropertyValue(id, \"host\");\n },\n\n /**\n * Determine the file's key name and passes it to the caller via a promissory callback. This also may\n * delegate to an integrator-defined function that determines the file's key name on demand,\n * which also may be promissory.\n *\n * @param id ID of the file\n * @param filename Name of the file\n * @returns {qq.Promise} A promise that will be fulfilled when the key name has been determined (and will be passed to the caller via the success callback).\n * @private\n */\n _determineKeyName: function(id, filename) {\n /*jshint -W015*/\n var promise = new qq.Promise(),\n keynameLogic = this._options.objectProperties.key,\n extension = qq.getExtension(filename),\n onGetKeynameFailure = promise.failure,\n onGetKeynameSuccess = function(keyname, extension) {\n var keynameToUse = keyname;\n\n if (extension !== undefined) {\n keynameToUse += \".\" + extension;\n }\n\n promise.success(keynameToUse);\n };\n\n switch (keynameLogic) {\n case \"uuid\":\n onGetKeynameSuccess(this.getUuid(id), extension);\n break;\n case \"filename\":\n onGetKeynameSuccess(filename);\n break;\n default:\n if (qq.isFunction(keynameLogic)) {\n this._handleKeynameFunction(keynameLogic, id, onGetKeynameSuccess, onGetKeynameFailure);\n }\n else {\n this.log(keynameLogic + \" is not a valid value for the s3.keyname option!\", \"error\");\n onGetKeynameFailure();\n }\n }\n\n return promise;\n },\n\n /**\n * Called by the internal onUpload handler if the integrator has supplied a function to determine\n * the file's key name. The integrator's function may be promissory. We also need to fulfill\n * the promise contract associated with the caller as well.\n *\n * @param keynameFunc Integrator-supplied function that must be executed to determine the key name. May be promissory.\n * @param id ID of the associated file\n * @param successCallback Invoke this if key name retrieval is successful, passing in the key name.\n * @param failureCallback Invoke this if key name retrieval was unsuccessful.\n * @private\n */\n _handleKeynameFunction: function(keynameFunc, id, successCallback, failureCallback) {\n var self = this,\n onSuccess = function(keyname) {\n successCallback(keyname);\n },\n onFailure = function(reason) {\n self.log(qq.format(\"Failed to retrieve key name for {}. Reason: {}\", id, reason || \"null\"), \"error\");\n failureCallback(reason);\n },\n keyname = keynameFunc.call(this, id);\n\n if (qq.isGenericPromise(keyname)) {\n keyname.then(onSuccess, onFailure);\n }\n /*jshint -W116*/\n else if (keyname == null) {\n onFailure();\n }\n else {\n onSuccess(keyname);\n }\n },\n\n _getEndpointSpecificParams: function(id, response, maybeXhr) {\n var params = {\n key: this.getKey(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n bucket: this.getBucket(id)\n };\n\n if (maybeXhr && maybeXhr.getResponseHeader(\"ETag\")) {\n params.etag = maybeXhr.getResponseHeader(\"ETag\");\n }\n else if (response.etag) {\n params.etag = response.etag;\n }\n\n return params;\n },\n\n // Hooks into the base internal `_onSubmitDelete` to add key and bucket params to the delete file request.\n _onSubmitDelete: function(id, onSuccessCallback) {\n var additionalMandatedParams = {\n key: this.getKey(id),\n bucket: this.getBucket(id)\n };\n\n return qq.FineUploaderBasic.prototype._onSubmitDelete.call(this, id, onSuccessCallback, additionalMandatedParams);\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.s3Key == null) {\n throw new qq.Error(\"Did not find s3Key property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedKeys[id] = sessionData.s3Key;\n this._cannedBuckets[id] = sessionData.s3Bucket;\n }\n\n return id;\n }\n });\n}());\n","/* globals qq, CryptoJS */\n\n// IE 10 does not support Uint8ClampedArray. We don't need it, but CryptoJS attempts to reference it\n// inside a conditional via an instanceof check, which breaks S3 v4 signatures for chunked uploads.\nif (!window.Uint8ClampedArray) {\n window.Uint8ClampedArray = function() {};\n}\n/**\n * Handles signature determination for HTML Form Upload requests and Multipart Uploader requests (via the S3 REST API).\n *\n * If the S3 requests are to be signed server side, this module will send a POST request to the server in an attempt\n * to solicit signatures for various S3-related requests. This module also parses the response and attempts\n * to determine if the effort was successful.\n *\n * If the S3 requests are to be signed client-side, without the help of a server, this module will utilize CryptoJS to\n * sign the requests directly in the browser and send them off to S3.\n *\n * @param o Options associated with all such requests\n * @returns {{getSignature: Function}} API method used to initiate the signature request.\n * @constructor\n */\nqq.s3.RequestSigner = function(o) {\n \"use strict\";\n\n var requester,\n thisSignatureRequester = this,\n pendingSignatures = {},\n options = {\n expectingPolicy: false,\n method: \"POST\",\n signatureSpec: {\n drift: 0,\n credentialsProvider: {},\n endpoint: null,\n customHeaders: {},\n version: 2\n },\n maxConnections: 3,\n endpointStore: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n },\n credentialsProvider,\n\n generateHeaders = function(signatureConstructor, signature, promise) {\n var headers = signatureConstructor.getHeaders();\n\n if (options.signatureSpec.version === 4) {\n headers.Authorization = qq.s3.util.V4_ALGORITHM_PARAM_VALUE +\n \" Credential=\" + options.signatureSpec.credentialsProvider.get().accessKey + \"/\" +\n qq.s3.util.getCredentialsDate(signatureConstructor.getRequestDate()) + \"/\" +\n options.signatureSpec.region + \"/\" +\n \"s3/aws4_request,\" +\n \"SignedHeaders=\" + signatureConstructor.getSignedHeaders() + \",\" +\n \"Signature=\" + signature;\n }\n else {\n headers.Authorization = \"AWS \" + options.signatureSpec.credentialsProvider.get().accessKey + \":\" + signature;\n }\n\n promise.success(headers, signatureConstructor.getEndOfUrl());\n },\n\n v2 = {\n getStringToSign: function(signatureSpec) {\n return qq.format(\"{}\\n{}\\n{}\\n\\n{}/{}/{}\",\n signatureSpec.method,\n signatureSpec.contentMd5 || \"\",\n signatureSpec.contentType || \"\",\n signatureSpec.headersStr || \"\\n\",\n signatureSpec.bucket,\n signatureSpec.endOfUrl);\n },\n\n signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {\n var headersWordArray = qq.CryptoJS.enc.Utf8.parse(headersStr),\n headersHmacSha1 = qq.CryptoJS.HmacSHA1(headersWordArray, credentialsProvider.get().secretKey),\n headersHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(headersHmacSha1);\n\n generateHeaders(signatureConstructor, headersHmacSha1Base64, signatureEffort);\n },\n\n signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var policyStr = JSON.stringify(policy),\n policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr),\n base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray),\n policyHmacSha1 = qq.CryptoJS.HmacSHA1(base64Policy, credentialsProvider.get().secretKey),\n policyHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(policyHmacSha1);\n\n signatureEffort.success({\n policy: base64Policy,\n signature: policyHmacSha1Base64\n }, updatedAccessKey, updatedSessionToken);\n }\n },\n\n v4 = {\n getCanonicalQueryString: function(endOfUri) {\n var queryParamIdx = endOfUri.indexOf(\"?\"),\n canonicalQueryString = \"\",\n encodedQueryParams, encodedQueryParamNames, queryStrings;\n\n if (queryParamIdx >= 0) {\n encodedQueryParams = {};\n queryStrings = endOfUri.substr(queryParamIdx + 1).split(\"&\");\n\n qq.each(queryStrings, function(idx, queryString) {\n var nameAndVal = queryString.split(\"=\"),\n paramVal = nameAndVal[1];\n\n if (paramVal == null) {\n paramVal = \"\";\n }\n\n encodedQueryParams[encodeURIComponent(nameAndVal[0])] = encodeURIComponent(paramVal);\n });\n\n encodedQueryParamNames = Object.keys(encodedQueryParams).sort();\n encodedQueryParamNames.forEach(function(encodedQueryParamName, idx) {\n canonicalQueryString += encodedQueryParamName + \"=\" + encodedQueryParams[encodedQueryParamName];\n if (idx < encodedQueryParamNames.length - 1) {\n canonicalQueryString += \"&\";\n }\n });\n }\n\n return canonicalQueryString;\n },\n\n getCanonicalRequest: function(signatureSpec) {\n return qq.format(\"{}\\n{}\\n{}\\n{}\\n{}\\n{}\",\n signatureSpec.method,\n v4.getCanonicalUri(signatureSpec.endOfUrl),\n v4.getCanonicalQueryString(signatureSpec.endOfUrl),\n signatureSpec.headersStr || \"\\n\",\n v4.getSignedHeaders(signatureSpec.headerNames),\n signatureSpec.hashedContent);\n },\n\n getCanonicalUri: function(endOfUri) {\n var path = endOfUri,\n queryParamIdx = endOfUri.indexOf(\"?\");\n\n if (queryParamIdx > 0) {\n path = endOfUri.substr(0, queryParamIdx);\n }\n return \"/\" + path;\n },\n\n getEncodedHashedPayload: function(body) {\n var promise = new qq.Promise(),\n reader;\n\n if (qq.isBlob(body)) {\n // TODO hash blob in webworker if this becomes a notable perf issue\n reader = new FileReader();\n reader.onloadend = function(e) {\n if (e.target.readyState === FileReader.DONE) {\n if (e.target.error) {\n promise.failure(e.target.error);\n }\n else {\n var wordArray = qq.CryptoJS.lib.WordArray.create(e.target.result);\n promise.success(qq.CryptoJS.SHA256(wordArray).toString());\n }\n }\n };\n reader.readAsArrayBuffer(body);\n }\n else {\n body = body || \"\";\n promise.success(qq.CryptoJS.SHA256(body).toString());\n }\n\n return promise;\n },\n\n getScope: function(date, region) {\n return qq.s3.util.getCredentialsDate(date) + \"/\" +\n region + \"/s3/aws4_request\";\n },\n\n getStringToSign: function(signatureSpec) {\n var canonicalRequest = v4.getCanonicalRequest(signatureSpec),\n date = qq.s3.util.getV4PolicyDate(signatureSpec.date, signatureSpec.drift),\n hashedRequest = qq.CryptoJS.SHA256(canonicalRequest).toString(),\n scope = v4.getScope(signatureSpec.date, options.signatureSpec.region),\n stringToSignTemplate = \"AWS4-HMAC-SHA256\\n{}\\n{}\\n{}\";\n\n return {\n hashed: qq.format(stringToSignTemplate, date, scope, hashedRequest),\n raw: qq.format(stringToSignTemplate, date, scope, canonicalRequest)\n };\n },\n\n getSignedHeaders: function(headerNames) {\n var signedHeaders = \"\";\n\n headerNames.forEach(function(headerName, idx) {\n signedHeaders += headerName.toLowerCase();\n\n if (idx < headerNames.length - 1) {\n signedHeaders += \";\";\n }\n });\n\n return signedHeaders;\n },\n\n signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {\n var secretKey = credentialsProvider.get().secretKey,\n headersPattern = /.+\\n.+\\n(\\d+)\\/(.+)\\/s3\\/.+\\n(.+)/,\n matches = headersPattern.exec(headersStr),\n dateKey, dateRegionKey, dateRegionServiceKey, signingKey;\n\n dateKey = qq.CryptoJS.HmacSHA256(matches[1], \"AWS4\" + secretKey);\n dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);\n dateRegionServiceKey = qq.CryptoJS.HmacSHA256(\"s3\", dateRegionKey);\n signingKey = qq.CryptoJS.HmacSHA256(\"aws4_request\", dateRegionServiceKey);\n\n generateHeaders(signatureConstructor, qq.CryptoJS.HmacSHA256(headersStr, signingKey), signatureEffort);\n },\n\n signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var policyStr = JSON.stringify(policy),\n policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr),\n base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray),\n secretKey = credentialsProvider.get().secretKey,\n credentialPattern = /.+\\/(.+)\\/(.+)\\/s3\\/aws4_request/,\n credentialCondition = (function() {\n var credential = null;\n qq.each(policy.conditions, function(key, condition) {\n var val = condition[\"x-amz-credential\"];\n if (val) {\n credential = val;\n return false;\n }\n });\n return credential;\n }()),\n matches, dateKey, dateRegionKey, dateRegionServiceKey, signingKey;\n\n matches = credentialPattern.exec(credentialCondition);\n dateKey = qq.CryptoJS.HmacSHA256(matches[1], \"AWS4\" + secretKey);\n dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);\n dateRegionServiceKey = qq.CryptoJS.HmacSHA256(\"s3\", dateRegionKey);\n signingKey = qq.CryptoJS.HmacSHA256(\"aws4_request\", dateRegionServiceKey);\n\n signatureEffort.success({\n policy: base64Policy,\n signature: qq.CryptoJS.HmacSHA256(base64Policy, signingKey).toString()\n }, updatedAccessKey, updatedSessionToken);\n }\n };\n\n qq.extend(options, o, true);\n credentialsProvider = options.signatureSpec.credentialsProvider;\n\n function handleSignatureReceived(id, xhrOrXdr, isError) {\n var responseJson = xhrOrXdr.responseText,\n pendingSignatureData = pendingSignatures[id],\n promise = pendingSignatureData.promise,\n signatureConstructor = pendingSignatureData.signatureConstructor,\n errorMessage, response;\n\n delete pendingSignatures[id];\n\n // Attempt to parse what we would expect to be a JSON response\n if (responseJson) {\n try {\n response = qq.parseJson(responseJson);\n }\n catch (error) {\n options.log(\"Error attempting to parse signature response: \" + error, \"error\");\n }\n }\n\n // If the response is parsable and contains an `error` property, use it as the error message\n if (response && response.error) {\n isError = true;\n errorMessage = response.error;\n }\n // If we have received a parsable response, and it has an `invalid` property,\n // the policy document or request headers may have been tampered with client-side.\n else if (response && response.invalid) {\n isError = true;\n errorMessage = \"Invalid policy document or request headers!\";\n }\n // Make sure the response contains policy & signature properties\n else if (response) {\n if (options.expectingPolicy && !response.policy) {\n isError = true;\n errorMessage = \"Response does not include the base64 encoded policy!\";\n }\n else if (!response.signature) {\n isError = true;\n errorMessage = \"Response does not include the signature!\";\n }\n }\n // Something unknown went wrong\n else {\n isError = true;\n errorMessage = \"Received an empty or invalid response from the server!\";\n }\n\n if (isError) {\n if (errorMessage) {\n options.log(errorMessage, \"error\");\n }\n\n promise.failure(errorMessage);\n }\n else if (signatureConstructor) {\n generateHeaders(signatureConstructor, response.signature, promise);\n }\n else {\n promise.success(response);\n }\n }\n\n function getStringToSignArtifacts(id, version, requestInfo) {\n var promise = new qq.Promise(),\n method = \"POST\",\n headerNames = [],\n headersStr = \"\",\n now = new Date(),\n endOfUrl, signatureSpec, toSign,\n\n generateStringToSign = function(requestInfo) {\n var contentMd5,\n headerIndexesToRemove = [];\n\n qq.each(requestInfo.headers, function(name) {\n headerNames.push(name);\n });\n headerNames.sort();\n\n qq.each(headerNames, function(idx, headerName) {\n if (qq.indexOf(qq.s3.util.UNSIGNABLE_REST_HEADER_NAMES, headerName) < 0) {\n headersStr += headerName.toLowerCase() + \":\" + requestInfo.headers[headerName].trim() + \"\\n\";\n }\n else if (headerName === \"Content-MD5\") {\n contentMd5 = requestInfo.headers[headerName];\n }\n else {\n headerIndexesToRemove.unshift(idx);\n }\n });\n\n qq.each(headerIndexesToRemove, function(idx, headerIdx) {\n headerNames.splice(headerIdx, 1);\n });\n\n signatureSpec = {\n bucket: requestInfo.bucket,\n contentMd5: contentMd5,\n contentType: requestInfo.contentType,\n date: now,\n drift: options.signatureSpec.drift,\n endOfUrl: endOfUrl,\n hashedContent: requestInfo.hashedContent,\n headerNames: headerNames,\n headersStr: headersStr,\n method: method\n };\n\n toSign = version === 2 ? v2.getStringToSign(signatureSpec) : v4.getStringToSign(signatureSpec);\n\n return {\n date: now,\n endOfUrl: endOfUrl,\n signedHeaders: version === 4 ? v4.getSignedHeaders(signatureSpec.headerNames) : null,\n toSign: version === 4 ? toSign.hashed : toSign,\n toSignRaw: version === 4 ? toSign.raw : toSign\n };\n };\n\n /*jshint indent:false */\n switch (requestInfo.type) {\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_ABORT:\n method = \"DELETE\";\n endOfUrl = qq.format(\"uploadId={}\", requestInfo.uploadId);\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_INITIATE:\n endOfUrl = \"uploads\";\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_COMPLETE:\n endOfUrl = qq.format(\"uploadId={}\", requestInfo.uploadId);\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_UPLOAD:\n method = \"PUT\";\n endOfUrl = qq.format(\"partNumber={}&uploadId={}\", requestInfo.partNum, requestInfo.uploadId);\n break;\n }\n\n endOfUrl = requestInfo.key + \"?\" + endOfUrl;\n\n if (version === 4) {\n v4.getEncodedHashedPayload(requestInfo.content).then(function(hashedContent) {\n requestInfo.headers[\"x-amz-content-sha256\"] = hashedContent;\n requestInfo.headers.Host = requestInfo.host;\n requestInfo.headers[\"x-amz-date\"] = qq.s3.util.getV4PolicyDate(now, options.signatureSpec.drift);\n requestInfo.hashedContent = hashedContent;\n\n promise.success(generateStringToSign(requestInfo));\n }, function (err) {\n promise.failure(err);\n });\n }\n else {\n promise.success(generateStringToSign(requestInfo));\n }\n\n return promise;\n }\n\n function determineSignatureClientSide(id, toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var updatedHeaders;\n\n // REST API request\n if (toBeSigned.signatureConstructor) {\n if (updatedSessionToken) {\n updatedHeaders = toBeSigned.signatureConstructor.getHeaders();\n updatedHeaders[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;\n toBeSigned.signatureConstructor.withHeaders(updatedHeaders);\n }\n\n toBeSigned.signatureConstructor.getToSign(id).then(function(signatureArtifacts) {\n signApiRequest(toBeSigned.signatureConstructor, signatureArtifacts.stringToSign, signatureEffort);\n }, function (err) {\n signatureEffort.failure(err);\n });\n }\n // Form upload (w/ policy document)\n else {\n updatedSessionToken && qq.s3.util.refreshPolicyCredentials(toBeSigned, updatedSessionToken);\n signPolicy(toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n }\n\n function signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n if (options.signatureSpec.version === 4) {\n v4.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n else {\n v2.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n }\n\n function signApiRequest(signatureConstructor, headersStr, signatureEffort) {\n if (options.signatureSpec.version === 4) {\n v4.signApiRequest(signatureConstructor, headersStr, signatureEffort);\n }\n else {\n v2.signApiRequest(signatureConstructor, headersStr, signatureEffort);\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n contentType: \"application/json; charset=utf-8\",\n endpointStore: {\n get: function() {\n return options.signatureSpec.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.signatureSpec.customHeaders,\n log: options.log,\n onComplete: handleSignatureReceived,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * On success, an object containing the parsed JSON response will be passed into the success handler if the\n * request succeeds. Otherwise an error message will be passed into the failure method.\n *\n * @param id File ID.\n * @param toBeSigned an Object that holds the item(s) to be signed\n * @returns {qq.Promise} A promise that is fulfilled when the response has been received.\n */\n getSignature: function(id, toBeSigned) {\n var params = toBeSigned,\n signatureConstructor = toBeSigned.signatureConstructor,\n signatureEffort = new qq.Promise(),\n queryParams;\n\n if (options.signatureSpec.version === 4) {\n queryParams = {v4: true};\n }\n\n if (credentialsProvider.get().secretKey && qq.CryptoJS) {\n if (credentialsProvider.get().expiration.getTime() > Date.now()) {\n determineSignatureClientSide(id, toBeSigned, signatureEffort);\n }\n // If credentials are expired, ask for new ones before attempting to sign request\n else {\n credentialsProvider.onExpired().then(function() {\n determineSignatureClientSide(id, toBeSigned,\n signatureEffort,\n credentialsProvider.get().accessKey,\n credentialsProvider.get().sessionToken);\n }, function(errorMsg) {\n options.log(\"Attempt to update expired credentials apparently failed! Unable to sign request. \", \"error\");\n signatureEffort.failure(\"Unable to sign request - expired credentials.\");\n });\n }\n }\n else {\n options.log(\"Submitting S3 signature request for \" + id);\n\n if (signatureConstructor) {\n signatureConstructor.getToSign(id).then(function(signatureArtifacts) {\n params = {headers: signatureArtifacts.stringToSignRaw};\n requester.initTransport(id)\n .withParams(params)\n .withQueryParams(queryParams)\n .send();\n }, function (err) {\n options.log(\"Failed to construct signature. \", \"error\");\n signatureEffort.failure(\"Failed to construct signature.\");\n });\n }\n else {\n requester.initTransport(id)\n .withParams(params)\n .withQueryParams(queryParams)\n .send();\n }\n\n pendingSignatures[id] = {\n promise: signatureEffort,\n signatureConstructor: signatureConstructor\n };\n }\n\n return signatureEffort;\n },\n\n constructStringToSign: function(type, bucket, host, key) {\n var headers = {},\n uploadId, content, contentType, partNum, artifacts;\n\n return {\n withHeaders: function(theHeaders) {\n headers = theHeaders;\n return this;\n },\n\n withUploadId: function(theUploadId) {\n uploadId = theUploadId;\n return this;\n },\n\n withContent: function(theContent) {\n content = theContent;\n return this;\n },\n\n withContentType: function(theContentType) {\n contentType = theContentType;\n return this;\n },\n\n withPartNum: function(thePartNum) {\n partNum = thePartNum;\n return this;\n },\n\n getToSign: function(id) {\n var sessionToken = credentialsProvider.get().sessionToken,\n promise = new qq.Promise(),\n adjustedDate = new Date(Date.now() + options.signatureSpec.drift);\n\n headers[\"x-amz-date\"] = adjustedDate.toUTCString();\n\n if (sessionToken) {\n headers[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n getStringToSignArtifacts(id, options.signatureSpec.version, {\n bucket: bucket,\n content: content,\n contentType: contentType,\n headers: headers,\n host: host,\n key: key,\n partNum: partNum,\n type: type,\n uploadId: uploadId\n }).then(function(_artifacts_) {\n artifacts = _artifacts_;\n promise.success({\n headers: (function() {\n if (contentType) {\n headers[\"Content-Type\"] = contentType;\n }\n\n delete headers.Host; // we don't want this to be set on the XHR-initiated request\n return headers;\n }()),\n date: artifacts.date,\n endOfUrl: artifacts.endOfUrl,\n signedHeaders: artifacts.signedHeaders,\n stringToSign: artifacts.toSign,\n stringToSignRaw: artifacts.toSignRaw\n });\n }, function (err) {\n promise.failure(err);\n });\n\n return promise;\n },\n\n getHeaders: function() {\n return qq.extend({}, headers);\n },\n\n getEndOfUrl: function() {\n return artifacts && artifacts.endOfUrl;\n },\n\n getRequestDate: function() {\n return artifacts && artifacts.date;\n },\n\n getSignedHeaders: function() {\n return artifacts && artifacts.signedHeaders;\n }\n };\n }\n });\n};\n\nqq.s3.RequestSigner.prototype.REQUEST_TYPE = {\n MULTIPART_INITIATE: \"multipart_initiate\",\n MULTIPART_COMPLETE: \"multipart_complete\",\n MULTIPART_ABORT: \"multipart_abort\",\n MULTIPART_UPLOAD: \"multipart_upload\"\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/*globals qq*/\n/**\n * Ajax requester used to send an [\"Initiate Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadInitiate.html)\n * request to S3 via the REST API.\n *\n * @param o Options from the caller - will override the defaults.\n * @constructor\n */\nqq.s3.InitiateMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingInitiateRequests = {},\n options = {\n filenameParam: \"qqfilename\",\n method: \"POST\",\n endpointStore: null,\n paramsStore: null,\n signatureSpec: null,\n aclStore: null,\n reducedRedundancy: false,\n serverSideEncryption: false,\n maxConnections: 3,\n getContentType: function(id) {},\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n getName: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Determine all headers for the \"Initiate MPU\" request, including the \"Authorization\" header, which must be determined\n * by the local server. This is a promissory function. If the server responds with a signature, the headers\n * (including the Authorization header) will be passed into the success method of the promise. Otherwise, the failure\n * method on the promise will be called.\n *\n * @param id Associated file ID\n * @returns {qq.Promise}\n */\n function getHeaders(id) {\n var bucket = options.getBucket(id),\n host = options.getHost(id),\n headers = {},\n promise = new qq.Promise(),\n key = options.getKey(id),\n signatureConstructor;\n\n headers[\"x-amz-acl\"] = options.aclStore.get(id);\n\n if (options.reducedRedundancy) {\n headers[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (options.serverSideEncryption) {\n headers[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n headers[qq.s3.util.AWS_PARAM_PREFIX + options.filenameParam] = encodeURIComponent(options.getName(id));\n\n qq.each(options.paramsStore.get(id), function(name, val) {\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {\n headers[name] = val;\n }\n else {\n headers[qq.s3.util.AWS_PARAM_PREFIX + name] = encodeURIComponent(val);\n }\n });\n\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_INITIATE, bucket, host, key)\n .withContentType(options.getContentType(id))\n .withHeaders(headers);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Initiate MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleInitiateRequestComplete(id, xhr, isError) {\n var promise = pendingInitiateRequests[id],\n domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n uploadIdElements, messageElements, uploadId, errorMessage, status;\n\n delete pendingInitiateRequests[id];\n\n // The base ajax requester may declare the request to be a failure based on status code.\n if (isError) {\n status = xhr.status;\n\n messageElements = responseDoc.getElementsByTagName(\"Message\");\n if (messageElements.length > 0) {\n errorMessage = messageElements[0].textContent;\n }\n }\n // If the base ajax requester has not declared this a failure, make sure we can retrieve the uploadId from the response.\n else {\n uploadIdElements = responseDoc.getElementsByTagName(\"UploadId\");\n if (uploadIdElements.length > 0) {\n uploadId = uploadIdElements[0].textContent;\n }\n else {\n errorMessage = \"Upload ID missing from request\";\n }\n }\n\n // Either fail the promise (passing a descriptive error message) or declare it a success (passing the upload ID)\n if (uploadId === undefined) {\n if (errorMessage) {\n options.log(qq.format(\"Specific problem detected initiating multipart upload request for {}: '{}'.\", id, errorMessage), \"error\");\n }\n else {\n options.log(qq.format(\"Unexplained error with initiate multipart upload request for {}. Status code {}.\", id, status), \"error\");\n }\n\n promise.failure(\"Problem initiating upload request.\", xhr);\n }\n else {\n options.log(qq.format(\"Initiate multipart upload request successful for {}. Upload ID is {}\", id, uploadId));\n promise.success(uploadId, xhr);\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n method: options.method,\n contentType: null,\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleInitiateRequestComplete,\n successfulResponseCodes: {\n POST: [200]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Initiate MPU\" request to AWS via the REST API. First, though, we must get a signature from the\n * local server for the request. If all is successful, the uploadId from AWS will be passed into the promise's\n * success handler. Otherwise, an error message will ultimately be passed into the failure method.\n *\n * @param id The ID associated with the file\n * @returns {qq.Promise}\n */\n send: function(id) {\n var promise = new qq.Promise();\n\n getHeaders(id).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 initiate multipart upload request for \" + id);\n\n pendingInitiateRequests[id] = promise;\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .send();\n }, promise.failure);\n\n return promise;\n }\n });\n};\n","/*globals qq*/\n/**\n * Ajax requester used to send an [\"Complete Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadComplete.html)\n * request to S3 via the REST API.\n *\n * @param o Options passed by the creator, to overwrite any default option values.\n * @constructor\n */\nqq.s3.CompleteMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingCompleteRequests = {},\n options = {\n method: \"POST\",\n contentType: \"text/xml\",\n endpointStore: null,\n signatureSpec: null,\n maxConnections: 3,\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n // Transport for requesting signatures (for the \"Complete\" requests) from the local server\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Attach all required headers (including Authorization) to the \"Complete\" request. This is a promissory function\n * that will fulfill the associated promise once all headers have been attached or when an error has occurred that\n * prevents headers from being attached.\n *\n * @returns {qq.Promise}\n */\n function getHeaders(id, uploadId, body) {\n var headers = {},\n promise = new qq.Promise(),\n bucket = options.getBucket(id),\n host = options.getHost(id),\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_COMPLETE, bucket, host, options.getKey(id))\n .withUploadId(uploadId)\n .withContent(body)\n .withContentType(\"application/xml; charset=UTF-8\");\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Complete MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleCompleteRequestComplete(id, xhr, isError) {\n var promise = pendingCompleteRequests[id],\n domParser = new DOMParser(),\n bucket = options.getBucket(id),\n key = options.getKey(id),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n bucketEls = responseDoc.getElementsByTagName(\"Bucket\"),\n keyEls = responseDoc.getElementsByTagName(\"Key\");\n\n delete pendingCompleteRequests[id];\n\n options.log(qq.format(\"Complete response status {}, body = {}\", xhr.status, xhr.responseText));\n\n // If the base requester has determine this a failure, give up.\n if (isError) {\n options.log(qq.format(\"Complete Multipart Upload request for {} failed with status {}.\", id, xhr.status), \"error\");\n }\n else {\n // Make sure the correct bucket and key has been specified in the XML response from AWS.\n if (bucketEls.length && keyEls.length) {\n if (bucketEls[0].textContent !== bucket) {\n isError = true;\n options.log(qq.format(\"Wrong bucket in response to Complete Multipart Upload request for {}.\", id), \"error\");\n }\n\n // TODO Compare key name from response w/ expected key name if AWS ever fixes the encoding of key names in this response.\n }\n else {\n isError = true;\n options.log(qq.format(\"Missing bucket and/or key in response to Complete Multipart Upload request for {}.\", id), \"error\");\n }\n }\n\n if (isError) {\n promise.failure(\"Problem combining the file parts!\", xhr);\n }\n else {\n promise.success({}, xhr);\n }\n }\n\n /**\n * @param etagEntries Array of objects containing `etag` values and their associated `part` numbers.\n * @returns {string} XML string containing the body to send with the \"Complete\" request\n */\n function getCompleteRequestBody(etagEntries) {\n var doc = document.implementation.createDocument(null, \"CompleteMultipartUpload\", null);\n\n // The entries MUST be sorted by part number, per the AWS API spec.\n etagEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(etagEntries, function(idx, etagEntry) {\n var part = etagEntry.part,\n etag = etagEntry.etag,\n partEl = doc.createElement(\"Part\"),\n partNumEl = doc.createElement(\"PartNumber\"),\n partNumTextEl = doc.createTextNode(part),\n etagTextEl = doc.createTextNode(etag),\n etagEl = doc.createElement(\"ETag\");\n\n etagEl.appendChild(etagTextEl);\n partNumEl.appendChild(partNumTextEl);\n partEl.appendChild(partNumEl);\n partEl.appendChild(etagEl);\n qq(doc).children()[0].appendChild(partEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n method: options.method,\n contentType: \"application/xml; charset=UTF-8\",\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleCompleteRequestComplete,\n successfulResponseCodes: {\n POST: [200]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Complete\" request and fulfills the returned promise when the success of this request is known.\n *\n * @param id ID associated with the file.\n * @param uploadId AWS uploadId for this file\n * @param etagEntries Array of objects containing `etag` values and their associated `part` numbers.\n * @returns {qq.Promise}\n */\n send: function(id, uploadId, etagEntries) {\n var promise = new qq.Promise(),\n body = getCompleteRequestBody(etagEntries);\n\n getHeaders(id, uploadId, body).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 complete multipart upload request for \" + id);\n\n pendingCompleteRequests[id] = promise;\n delete headers[\"Content-Type\"];\n\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .withPayload(body)\n .send();\n }, promise.failure);\n\n return promise;\n }\n });\n};\n","/*globals qq */\n/**\n * Ajax requester used to send an [\"Abort Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadAbort.html)\n * request to S3 via the REST API.\n\n * @param o\n * @constructor\n */\nqq.s3.AbortMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n endpointStore: null,\n signatureSpec: null,\n maxConnections: 3,\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n // Transport for requesting signatures (for the \"Complete\" requests) from the local server\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Attach all required headers (including Authorization) to the \"Abort\" request. This is a promissory function\n * that will fulfill the associated promise once all headers have been attached or when an error has occurred that\n * prevents headers from being attached.\n *\n * @param id Associated file ID\n * @param uploadId ID of the associated upload, according to AWS\n * @returns {qq.Promise}\n */\n function getHeaders(id, uploadId) {\n var headers = {},\n promise = new qq.Promise(),\n bucket = options.getBucket(id),\n host = options.getHost(id),\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, options.getKey(id))\n .withUploadId(uploadId);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Abort MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleAbortRequestComplete(id, xhr, isError) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n errorEls = responseDoc.getElementsByTagName(\"Error\"),\n awsErrorMsg;\n\n options.log(qq.format(\"Abort response status {}, body = {}\", xhr.status, xhr.responseText));\n\n // If the base requester has determine this a failure, give up.\n if (isError) {\n options.log(qq.format(\"Abort Multipart Upload request for {} failed with status {}.\", id, xhr.status), \"error\");\n }\n else {\n // Make sure the correct bucket and key has been specified in the XML response from AWS.\n if (errorEls.length) {\n isError = true;\n awsErrorMsg = responseDoc.getElementsByTagName(\"Message\")[0].textContent;\n options.log(qq.format(\"Failed to Abort Multipart Upload request for {}. Error: {}\", id, awsErrorMsg), \"error\");\n }\n else {\n options.log(qq.format(\"Abort MPU request succeeded for file ID {}.\", id));\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [\"DELETE\"],\n method: options.method,\n contentType: null,\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleAbortRequestComplete,\n successfulResponseCodes: {\n DELETE: [204]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Abort\" request.\n *\n * @param id ID associated with the file.\n * @param uploadId AWS uploadId for this file\n */\n send: function(id, uploadId) {\n getHeaders(id, uploadId).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 Abort multipart upload request for \" + id);\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .send();\n });\n }\n });\n};\n","/*globals qq */\n/**\n * Upload handler used by the upload to S3 module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to S3 buckets via the associated AWS API.\n *\n * If chunking is supported and enabled, the S3 Multipart Upload REST API is utilized.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.s3.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var getName = proxy.getName,\n log = proxy.log,\n clockDrift = spec.clockDrift,\n expectedStatus = 200,\n onGetBucket = spec.getBucket,\n onGetHost = spec.getHost,\n onGetKeyName = spec.getKeyName,\n filenameParam = spec.filenameParam,\n paramsStore = spec.paramsStore,\n endpointStore = spec.endpointStore,\n aclStore = spec.aclStore,\n reducedRedundancy = spec.objectProperties.reducedRedundancy,\n region = spec.objectProperties.region,\n serverSideEncryption = spec.objectProperties.serverSideEncryption,\n validation = spec.validation,\n signature = qq.extend({region: region, drift: clockDrift}, spec.signature),\n handler = this,\n credentialsProvider = spec.signature.credentialsProvider,\n\n chunked = {\n // Sends a \"Complete Multipart Upload\" request and then signals completion of the upload\n // when the response to this request has been parsed.\n combine: function(id) {\n var uploadId = handler._getPersistableData(id).uploadId,\n etagMap = handler._getPersistableData(id).etags,\n result = new qq.Promise();\n\n requesters.completeMultipart.send(id, uploadId, etagMap).then(\n result.success,\n\n function failure(reason, xhr) {\n result.failure(upload.done(id, xhr).response, xhr);\n }\n );\n\n return result;\n },\n\n // The last step in handling a chunked upload. This is called after each chunk has been sent.\n // The request may be successful, or not. If it was successful, we must extract the \"ETag\" element\n // in the XML response and store that along with the associated part number.\n // We need these items to \"Complete\" the multipart upload after all chunks have been successfully sent.\n done: function(id, xhr, chunkIdx) {\n var response = upload.response.parse(id, xhr),\n etag;\n\n if (response.success) {\n etag = xhr.getResponseHeader(\"ETag\");\n\n if (!handler._getPersistableData(id).etags) {\n handler._getPersistableData(id).etags = [];\n }\n handler._getPersistableData(id).etags.push({part: chunkIdx + 1, etag: etag});\n }\n },\n\n /**\n * Determines headers that must be attached to the chunked (Multipart Upload) request. One of these headers is an\n * Authorization value, which must be determined by asking the local server to sign the request first. So, this\n * function returns a promise. Once all headers are determined, the `success` method of the promise is called with\n * the headers object. If there was some problem determining the headers, we delegate to the caller's `failure`\n * callback.\n *\n * @param id File ID\n * @param chunkIdx Index of the chunk to PUT\n * @returns {qq.Promise}\n */\n initHeaders: function(id, chunkIdx, blob) {\n var headers = {},\n bucket = upload.bucket.getName(id),\n host = upload.host.getName(id),\n key = upload.key.urlSafe(id),\n promise = new qq.Promise(),\n signatureConstructor = requesters.restSignature.constructStringToSign\n (requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key)\n .withPartNum(chunkIdx + 1)\n .withContent(blob)\n .withUploadId(handler._getPersistableData(id).uploadId);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n requesters.restSignature.getSignature(id + \".\" + chunkIdx, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n },\n\n put: function(id, chunkIdx) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx),\n domain = spec.endpointStore.get(id),\n promise = new qq.Promise();\n\n // Add appropriate headers to the multipart upload request.\n // Once these have been determined (asynchronously) attach the headers and send the chunk.\n chunked.initHeaders(id, chunkIdx, chunkData.blob).then(function(headers, endOfUrl) {\n if (xhr._cancelled) {\n log(qq.format(\"Upload of item {}.{} cancelled. Upload will not start after successful signature request.\", id, chunkIdx));\n promise.failure({error: \"Chunk upload cancelled\"});\n }\n else {\n var url = domain + \"/\" + endOfUrl;\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n upload.track(id, xhr, chunkIdx).then(promise.success, promise.failure);\n xhr.open(\"PUT\", url, true);\n\n qq.each(headers, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n\n xhr.send(chunkData.blob);\n }\n }, function() {\n promise.failure({error: \"Problem signing the chunk!\"}, xhr);\n });\n\n return promise;\n },\n\n send: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n chunked.setup(id).then(\n // The \"Initiate\" request succeeded. We are ready to send the first chunk.\n function() {\n chunked.put(id, chunkIdx).then(promise.success, promise.failure);\n },\n\n // We were unable to initiate the chunked upload process.\n function(errorMessage, xhr) {\n promise.failure({error: errorMessage}, xhr);\n }\n );\n\n return promise;\n },\n\n /**\n * Sends an \"Initiate Multipart Upload\" request to S3 via the REST API, but only if the MPU has not already been\n * initiated.\n *\n * @param id Associated file ID\n * @returns {qq.Promise} A promise that is fulfilled when the initiate request has been sent and the response has been parsed.\n */\n setup: function(id) {\n var promise = new qq.Promise(),\n uploadId = handler._getPersistableData(id).uploadId,\n uploadIdPromise = new qq.Promise();\n\n if (!uploadId) {\n handler._getPersistableData(id).uploadId = uploadIdPromise;\n requesters.initiateMultipart.send(id).then(\n function(uploadId) {\n handler._getPersistableData(id).uploadId = uploadId;\n uploadIdPromise.success(uploadId);\n promise.success(uploadId);\n },\n function(errorMsg, xhr) {\n handler._getPersistableData(id).uploadId = null;\n promise.failure(errorMsg, xhr);\n uploadIdPromise.failure(errorMsg, xhr);\n }\n );\n }\n else if (uploadId instanceof qq.Promise) {\n uploadId.then(function(uploadId) {\n promise.success(uploadId);\n });\n }\n else {\n promise.success(uploadId);\n }\n\n return promise;\n }\n },\n\n requesters = {\n abortMultipart: new qq.s3.AbortMultipartAjaxRequester({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log,\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n }\n }),\n\n completeMultipart: new qq.s3.CompleteMultipartAjaxRequester({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log,\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n }\n }),\n\n initiateMultipart: new qq.s3.InitiateMultipartAjaxRequester({\n filenameParam: filenameParam,\n endpointStore: endpointStore,\n paramsStore: paramsStore,\n signatureSpec: signature,\n aclStore: aclStore,\n reducedRedundancy: reducedRedundancy,\n serverSideEncryption: serverSideEncryption,\n cors: spec.cors,\n log: log,\n getContentType: function(id) {\n return handler._getMimeType(id);\n },\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n },\n getName: function(id) {\n return getName(id);\n }\n }),\n\n policySignature: new qq.s3.RequestSigner({\n expectingPolicy: true,\n signatureSpec: signature,\n cors: spec.cors,\n log: log\n }),\n\n restSignature: new qq.s3.RequestSigner({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log\n })\n },\n\n simple = {\n /**\n * Used for simple (non-chunked) uploads to determine the parameters to send along with the request. Part of this\n * process involves asking the local server to sign the request, so this function returns a promise. The promise\n * is fulfilled when all parameters are determined, or when we determine that all parameters cannot be calculated\n * due to some error.\n *\n * @param id File ID\n * @returns {qq.Promise}\n */\n initParams: function(id) {\n /*jshint -W040 */\n var customParams = paramsStore.get(id);\n customParams[filenameParam] = getName(id);\n\n return qq.s3.util.generateAwsParams({\n endpoint: endpointStore.get(id),\n clockDrift: clockDrift,\n params: customParams,\n type: handler._getMimeType(id),\n bucket: upload.bucket.getName(id),\n key: handler.getThirdPartyFileId(id),\n accessKey: credentialsProvider.get().accessKey,\n sessionToken: credentialsProvider.get().sessionToken,\n acl: aclStore.get(id),\n expectedStatus: expectedStatus,\n minFileSize: validation.minSizeLimit,\n maxFileSize: validation.maxSizeLimit,\n reducedRedundancy: reducedRedundancy,\n region: region,\n serverSideEncryption: serverSideEncryption,\n signatureVersion: signature.version,\n log: log\n },\n qq.bind(requesters.policySignature.getSignature, this, id));\n },\n\n send: function(id) {\n var promise = new qq.Promise(),\n xhr = handler._createXhr(id),\n fileOrBlob = handler.getFile(id);\n\n handler._registerProgressHandler(id);\n upload.track(id, xhr).then(promise.success, promise.failure);\n\n // Delegate to a function the sets up the XHR request and notifies us when it is ready to be sent, along w/ the payload.\n simple.setup(id, xhr, fileOrBlob).then(function(toSend) {\n log(\"Sending upload request for \" + id);\n xhr.send(toSend);\n }, promise.failure);\n\n return promise;\n },\n\n /**\n * Starts the upload process by delegating to an async function that determine parameters to be attached to the\n * request. If all params can be determined, we are called back with the params and the caller of this function is\n * informed by invoking the `success` method on the promise returned by this function, passing the payload of the\n * request. If some error occurs here, we delegate to a function that signals a failure for this upload attempt.\n *\n * Note that this is only used by the simple (non-chunked) upload process.\n *\n * @param id File ID\n * @param xhr XMLHttpRequest to use for the upload\n * @param fileOrBlob `File` or `Blob` to send\n * @returns {qq.Promise}\n */\n setup: function(id, xhr, fileOrBlob) {\n var formData = new FormData(),\n endpoint = endpointStore.get(id),\n url = endpoint,\n promise = new qq.Promise();\n\n simple.initParams(id).then(\n // Success - all params determined\n function(awsParams) {\n xhr.open(\"POST\", url, true);\n\n qq.obj2FormData(awsParams, formData);\n\n // AWS requires the file field be named \"file\".\n formData.append(\"file\", fileOrBlob);\n\n promise.success(formData);\n },\n\n // Failure - we couldn't determine some params (likely the signature)\n function(errorMessage) {\n promise.failure({error: errorMessage});\n }\n );\n\n return promise;\n }\n },\n\n upload = {\n /**\n * Note that this is called when an upload has reached a termination point,\n * regardless of success/failure. For example, it is called when we have\n * encountered an error during the upload or when the file may have uploaded successfully.\n *\n * @param id file ID\n */\n bucket: {\n promise: function(id) {\n var promise = new qq.Promise(),\n cachedBucket = handler._getFileState(id).bucket;\n\n if (cachedBucket) {\n promise.success(cachedBucket);\n }\n else {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n promise.success(bucket);\n }, promise.failure);\n }\n\n return promise;\n },\n\n getName: function(id) {\n return handler._getFileState(id).bucket;\n }\n },\n\n host: {\n promise: function(id) {\n var promise = new qq.Promise(),\n cachedHost = handler._getFileState(id).host;\n\n if (cachedHost) {\n promise.success(cachedHost);\n }\n else {\n onGetHost(id).then(function(host) {\n handler._getFileState(id).host = host;\n promise.success(host);\n }, promise.failure);\n }\n\n return promise;\n },\n\n getName: function(id) {\n return handler._getFileState(id).host;\n }\n },\n\n done: function(id, xhr) {\n var response = upload.response.parse(id, xhr),\n isError = response.success !== true;\n\n if (isError && upload.response.shouldReset(response.code)) {\n log(\"This is an unrecoverable error, we must restart the upload entirely on the next retry attempt.\", \"error\");\n response.reset = true;\n }\n\n return {\n success: !isError,\n response: response\n };\n },\n\n key: {\n promise: function(id) {\n var promise = new qq.Promise(),\n key = handler.getThirdPartyFileId(id);\n\n /* jshint eqnull:true */\n if (key == null) {\n handler._setThirdPartyFileId(id, promise);\n onGetKeyName(id, getName(id)).then(\n function(keyName) {\n handler._setThirdPartyFileId(id, keyName);\n promise.success(keyName);\n },\n function(errorReason) {\n handler._setThirdPartyFileId(id, null);\n promise.failure(errorReason);\n }\n );\n }\n else if (qq.isGenericPromise(key)) {\n key.then(promise.success, promise.failure);\n }\n else {\n promise.success(key);\n }\n\n return promise;\n },\n\n urlSafe: function(id) {\n var encodedKey = handler.getThirdPartyFileId(id);\n return qq.s3.util.uriEscapePath(encodedKey);\n }\n },\n\n response: {\n parse: function(id, xhr) {\n var response = {},\n parsedErrorProps;\n\n try {\n log(qq.format(\"Received response status {} with body: {}\", xhr.status, xhr.responseText));\n\n if (xhr.status === expectedStatus) {\n response.success = true;\n }\n else {\n parsedErrorProps = upload.response.parseError(xhr.responseText);\n\n if (parsedErrorProps) {\n response.error = parsedErrorProps.message;\n response.code = parsedErrorProps.code;\n }\n }\n }\n catch (error) {\n log(\"Error when attempting to parse xhr response text (\" + error.message + \")\", \"error\");\n }\n\n return response;\n },\n\n /**\n * This parses an XML response by extracting the \"Message\" and \"Code\" elements that accompany AWS error responses.\n *\n * @param awsResponseXml XML response from AWS\n * @returns {object} Object w/ `code` and `message` properties, or undefined if we couldn't find error info in the XML document.\n */\n parseError: function(awsResponseXml) {\n var parser = new DOMParser(),\n parsedDoc = parser.parseFromString(awsResponseXml, \"application/xml\"),\n errorEls = parsedDoc.getElementsByTagName(\"Error\"),\n errorDetails = {},\n codeEls, messageEls;\n\n if (errorEls.length) {\n codeEls = parsedDoc.getElementsByTagName(\"Code\");\n messageEls = parsedDoc.getElementsByTagName(\"Message\");\n\n if (messageEls.length) {\n errorDetails.message = messageEls[0].textContent;\n }\n\n if (codeEls.length) {\n errorDetails.code = codeEls[0].textContent;\n }\n\n return errorDetails;\n }\n },\n\n // Determine if the upload should be restarted on the next retry attempt\n // based on the error code returned in the response from AWS.\n shouldReset: function(errorCode) {\n /*jshint -W014 */\n return errorCode === \"EntityTooSmall\"\n || errorCode === \"InvalidPart\"\n || errorCode === \"InvalidPartOrder\"\n || errorCode === \"NoSuchUpload\";\n }\n },\n\n start: function(id, optChunkIdx) {\n var promise = new qq.Promise();\n\n upload.key.promise(id).then(function() {\n upload.bucket.promise(id).then(function() {\n upload.host.promise(id).then(function() {\n /* jshint eqnull:true */\n if (optChunkIdx == null) {\n simple.send(id).then(promise.success, promise.failure);\n }\n else {\n chunked.send(id, optChunkIdx).then(promise.success, promise.failure);\n }\n });\n });\n },\n function(errorReason) {\n promise.failure({error: errorReason});\n });\n\n return promise;\n },\n\n track: function(id, xhr, optChunkIdx) {\n var promise = new qq.Promise();\n\n xhr.onreadystatechange = function() {\n if (xhr.readyState === 4) {\n var result;\n\n /* jshint eqnull:true */\n if (optChunkIdx == null) {\n result = upload.done(id, xhr);\n promise[result.success ? \"success\" : \"failure\"](result.response, xhr);\n }\n else {\n chunked.done(id, xhr, optChunkIdx);\n result = upload.done(id, xhr);\n promise[result.success ? \"success\" : \"failure\"](result.response, xhr);\n }\n }\n };\n\n return promise;\n }\n };\n\n qq.extend(this, {\n uploadChunk: upload.start,\n uploadFile: upload.start\n });\n\n qq.extend(this, new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"s3\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var uploadId = handler._getPersistableData(id) && handler._getPersistableData(id).uploadId,\n existedInLocalStorage = handler._maybeDeletePersistedChunkData(id);\n\n if (uploadId !== undefined && existedInLocalStorage) {\n requesters.abortMultipart.send(id, uploadId);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return chunked.combine(id);\n },\n\n _getLocalStorageId: function(id) {\n var baseStorageId = super_._getLocalStorageId(id),\n bucketName = upload.bucket.getName(id);\n\n return baseStorageId + \"-\" + bucketName;\n }\n };\n });\n};\n","/*globals qq */\n/**\n * Upload handler used by the upload to S3 module that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to S3 buckets via the associated\n * AWS API.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.s3.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n clockDrift = options.clockDrift,\n onUuidChanged = proxy.onUuidChanged,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n onGetBucket = options.getBucket,\n onGetKeyName = options.getKeyName,\n filenameParam = options.filenameParam,\n paramsStore = options.paramsStore,\n endpointStore = options.endpointStore,\n aclStore = options.aclStore,\n reducedRedundancy = options.objectProperties.reducedRedundancy,\n region = options.objectProperties.region,\n serverSideEncryption = options.objectProperties.serverSideEncryption,\n validation = options.validation,\n signature = options.signature,\n successRedirectUrl = options.iframeSupport.localBlankPagePath,\n credentialsProvider = options.signature.credentialsProvider,\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n signatureSpec: signature,\n cors: options.cors,\n log: log\n });\n\n if (successRedirectUrl === undefined) {\n throw new Error(\"successRedirectEndpoint MUST be defined if you intend to use browsers that do not support the File API!\");\n }\n\n /**\n * Attempt to parse the contents of an iframe after receiving a response from the server. If the contents cannot be\n * read (perhaps due to a security error) it is safe to assume that the upload was not successful since Amazon should\n * have redirected to a known endpoint that should provide a parseable response.\n *\n * @param id ID of the associated file\n * @param iframe target of the form submit\n * @returns {boolean} true if the contents can be read, false otherwise\n */\n function isValidResponse(id, iframe) {\n var response,\n endpoint = options.endpointStore.get(id),\n bucket = handler._getFileState(id).bucket,\n doc,\n innerHtml,\n responseData;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n responseData = qq.s3.util.parseIframeResponse(iframe);\n if (responseData.bucket === bucket &&\n responseData.key === qq.s3.util.encodeQueryStringParam(handler.getThirdPartyFileId(id))) {\n\n return true;\n }\n\n log(\"Response from AWS included an unexpected bucket or key name.\", \"error\");\n\n }\n catch (error) {\n log(\"Error when attempting to parse form upload response (\" + error.message + \")\", \"error\");\n }\n\n return false;\n }\n\n function generateAwsParams(id) {\n /*jshint -W040 */\n var customParams = paramsStore.get(id);\n\n customParams[filenameParam] = getName(id);\n\n return qq.s3.util.generateAwsParams({\n endpoint: endpointStore.get(id),\n clockDrift: clockDrift,\n params: customParams,\n bucket: handler._getFileState(id).bucket,\n key: handler.getThirdPartyFileId(id),\n accessKey: credentialsProvider.get().accessKey,\n sessionToken: credentialsProvider.get().sessionToken,\n acl: aclStore.get(id),\n minFileSize: validation.minSizeLimit,\n maxFileSize: validation.maxSizeLimit,\n successRedirectUrl: successRedirectUrl,\n reducedRedundancy: reducedRedundancy,\n region: region,\n serverSideEncryption: serverSideEncryption,\n signatureVersion: signature.version,\n log: log\n },\n qq.bind(getSignatureAjaxRequester.getSignature, this, id));\n }\n\n /**\n * Creates form, that will be submitted to iframe\n */\n function createForm(id, iframe) {\n var promise = new qq.Promise(),\n method = \"POST\",\n endpoint = options.endpointStore.get(id),\n fileName = getName(id);\n\n generateAwsParams(id).then(function(params) {\n var form = handler._initFormForUpload({\n method: method,\n endpoint: endpoint,\n params: params,\n paramsInBody: true,\n targetName: iframe.name\n });\n\n promise.success(form);\n }, function(errorMessage) {\n promise.failure(errorMessage);\n handleFinishedUpload(id, iframe, fileName, {error: errorMessage});\n });\n\n return promise;\n }\n\n function handleUpload(id) {\n var iframe = handler._createIframe(id),\n input = handler.getInput(id),\n promise = new qq.Promise();\n\n createForm(id, iframe).then(function(form) {\n form.appendChild(input);\n\n // Register a callback when the response comes in from S3\n handler._attachLoadEvent(iframe, function(response) {\n log(\"iframe loaded\");\n\n // If the common response handler has determined success or failure immediately\n if (response) {\n // If there is something fundamentally wrong with the response (such as iframe content is not accessible)\n if (response.success === false) {\n log(\"Amazon likely rejected the upload request\", \"error\");\n promise.failure(response);\n }\n }\n // The generic response (iframe onload) handler was not able to make a determination regarding the success of the request\n else {\n response = {};\n response.success = isValidResponse(id, iframe);\n\n // If the more specific response handle detected a problem with the response from S3\n if (response.success === false) {\n log(\"A success response was received by Amazon, but it was invalid in some way.\", \"error\");\n promise.failure(response);\n }\n else {\n qq.extend(response, qq.s3.util.parseIframeResponse(iframe));\n promise.success(response);\n }\n }\n\n handleFinishedUpload(id, iframe);\n });\n\n log(\"Sending upload request for \" + id);\n form.submit();\n qq(form).remove();\n }, promise.failure);\n\n return promise;\n }\n\n function handleFinishedUpload(id, iframe) {\n handler._detachLoadEvent(id);\n iframe && qq(iframe).remove();\n }\n\n qq.extend(this, new qq.FormUploadHandler({\n options: {\n isCors: false,\n inputName: \"file\"\n },\n\n proxy: {\n onCancel: options.onCancel,\n onUuidChanged: onUuidChanged,\n getName: getName,\n getUuid: getUuid,\n log: log\n }\n }));\n\n qq.extend(this, {\n uploadFile: function(id) {\n var name = getName(id),\n promise = new qq.Promise();\n\n if (handler.getThirdPartyFileId(id)) {\n if (handler._getFileState(id).bucket) {\n handleUpload(id).then(promise.success, promise.failure);\n }\n else {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n handleUpload(id).then(promise.success, promise.failure);\n });\n }\n }\n else {\n // The S3 uploader module will either calculate the key or ask the server for it\n // and will call us back once it is known.\n onGetKeyName(id, name).then(function(key) {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n handler._setThirdPartyFileId(id, key);\n handleUpload(id).then(promise.success, promise.failure);\n }, function(errorReason) {\n promise.failure({error: errorReason});\n });\n }, function(errorReason) {\n promise.failure({error: errorReason});\n });\n }\n\n return promise;\n }\n });\n};\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.js b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.js
new file mode 100644
index 000000000000..ec1409a54e8b
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.js
@@ -0,0 +1,10632 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+(function(global) {
+ var qq = function(element) {
+ "use strict";
+ return {
+ hide: function() {
+ element.style.display = "none";
+ return this;
+ },
+ attach: function(type, fn) {
+ if (element.addEventListener) {
+ element.addEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.attachEvent("on" + type, fn);
+ }
+ return function() {
+ qq(element).detach(type, fn);
+ };
+ },
+ detach: function(type, fn) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.detachEvent("on" + type, fn);
+ }
+ return this;
+ },
+ contains: function(descendant) {
+ if (!descendant) {
+ return false;
+ }
+ if (element === descendant) {
+ return true;
+ }
+ if (element.contains) {
+ return element.contains(descendant);
+ } else {
+ return !!(descendant.compareDocumentPosition(element) & 8);
+ }
+ },
+ insertBefore: function(elementB) {
+ elementB.parentNode.insertBefore(element, elementB);
+ return this;
+ },
+ remove: function() {
+ element.parentNode.removeChild(element);
+ return this;
+ },
+ css: function(styles) {
+ if (element.style == null) {
+ throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");
+ }
+ if (styles.opacity != null) {
+ if (typeof element.style.opacity !== "string" && typeof element.filters !== "undefined") {
+ styles.filter = "alpha(opacity=" + Math.round(100 * styles.opacity) + ")";
+ }
+ }
+ qq.extend(element.style, styles);
+ return this;
+ },
+ hasClass: function(name, considerParent) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));
+ },
+ addClass: function(name) {
+ if (!qq(element).hasClass(name)) {
+ element.className += " " + name;
+ }
+ return this;
+ },
+ removeClass: function(name) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ element.className = element.className.replace(re, " ").replace(/^\s+|\s+$/g, "");
+ return this;
+ },
+ getByClass: function(className, first) {
+ var candidates, result = [];
+ if (first && element.querySelector) {
+ return element.querySelector("." + className);
+ } else if (element.querySelectorAll) {
+ return element.querySelectorAll("." + className);
+ }
+ candidates = element.getElementsByTagName("*");
+ qq.each(candidates, function(idx, val) {
+ if (qq(val).hasClass(className)) {
+ result.push(val);
+ }
+ });
+ return first ? result[0] : result;
+ },
+ getFirstByClass: function(className) {
+ return qq(element).getByClass(className, true);
+ },
+ children: function() {
+ var children = [], child = element.firstChild;
+ while (child) {
+ if (child.nodeType === 1) {
+ children.push(child);
+ }
+ child = child.nextSibling;
+ }
+ return children;
+ },
+ setText: function(text) {
+ element.innerText = text;
+ element.textContent = text;
+ return this;
+ },
+ clearText: function() {
+ return qq(element).setText("");
+ },
+ hasAttribute: function(attrName) {
+ var attrVal;
+ if (element.hasAttribute) {
+ if (!element.hasAttribute(attrName)) {
+ return false;
+ }
+ return /^false$/i.exec(element.getAttribute(attrName)) == null;
+ } else {
+ attrVal = element[attrName];
+ if (attrVal === undefined) {
+ return false;
+ }
+ return /^false$/i.exec(attrVal) == null;
+ }
+ }
+ };
+ };
+ (function() {
+ "use strict";
+ qq.canvasToBlob = function(canvas, mime, quality) {
+ return qq.dataUriToBlob(canvas.toDataURL(mime, quality));
+ };
+ qq.dataUriToBlob = function(dataUri) {
+ var arrayBuffer, byteString, createBlob = function(data, mime) {
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }, intArray, mimeString;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return createBlob(arrayBuffer, mimeString);
+ };
+ qq.log = function(message, level) {
+ if (window.console) {
+ if (!level || level === "info") {
+ window.console.log(message);
+ } else {
+ if (window.console[level]) {
+ window.console[level](message);
+ } else {
+ window.console.log("<" + level + "> " + message);
+ }
+ }
+ }
+ };
+ qq.isObject = function(variable) {
+ return variable && !variable.nodeType && Object.prototype.toString.call(variable) === "[object Object]";
+ };
+ qq.isFunction = function(variable) {
+ return typeof variable === "function";
+ };
+ qq.isArray = function(value) {
+ return Object.prototype.toString.call(value) === "[object Array]" || value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer;
+ };
+ qq.isItemList = function(maybeItemList) {
+ return Object.prototype.toString.call(maybeItemList) === "[object DataTransferItemList]";
+ };
+ qq.isNodeList = function(maybeNodeList) {
+ return Object.prototype.toString.call(maybeNodeList) === "[object NodeList]" || maybeNodeList.item && maybeNodeList.namedItem;
+ };
+ qq.isString = function(maybeString) {
+ return Object.prototype.toString.call(maybeString) === "[object String]";
+ };
+ qq.trimStr = function(string) {
+ if (String.prototype.trim) {
+ return string.trim();
+ }
+ return string.replace(/^\s+|\s+$/g, "");
+ };
+ qq.format = function(str) {
+ var args = Array.prototype.slice.call(arguments, 1), newStr = str, nextIdxToReplace = newStr.indexOf("{}");
+ qq.each(args, function(idx, val) {
+ var strBefore = newStr.substring(0, nextIdxToReplace), strAfter = newStr.substring(nextIdxToReplace + 2);
+ newStr = strBefore + val + strAfter;
+ nextIdxToReplace = newStr.indexOf("{}", nextIdxToReplace + val.length);
+ if (nextIdxToReplace < 0) {
+ return false;
+ }
+ });
+ return newStr;
+ };
+ qq.isFile = function(maybeFile) {
+ return window.File && Object.prototype.toString.call(maybeFile) === "[object File]";
+ };
+ qq.isFileList = function(maybeFileList) {
+ return window.FileList && Object.prototype.toString.call(maybeFileList) === "[object FileList]";
+ };
+ qq.isFileOrInput = function(maybeFileOrInput) {
+ return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);
+ };
+ qq.isInput = function(maybeInput, notFile) {
+ var evaluateType = function(type) {
+ var normalizedType = type.toLowerCase();
+ if (notFile) {
+ return normalizedType !== "file";
+ }
+ return normalizedType === "file";
+ };
+ if (window.HTMLInputElement) {
+ if (Object.prototype.toString.call(maybeInput) === "[object HTMLInputElement]") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ if (maybeInput.tagName) {
+ if (maybeInput.tagName.toLowerCase() === "input") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ qq.isBlob = function(maybeBlob) {
+ if (window.Blob && Object.prototype.toString.call(maybeBlob) === "[object Blob]") {
+ return true;
+ }
+ };
+ qq.isXhrUploadSupported = function() {
+ var input = document.createElement("input");
+ input.type = "file";
+ return input.multiple !== undefined && typeof File !== "undefined" && typeof FormData !== "undefined" && typeof qq.createXhrInstance().upload !== "undefined";
+ };
+ qq.createXhrInstance = function() {
+ if (window.XMLHttpRequest) {
+ return new XMLHttpRequest();
+ }
+ try {
+ return new ActiveXObject("MSXML2.XMLHTTP.3.0");
+ } catch (error) {
+ qq.log("Neither XHR or ActiveX are supported!", "error");
+ return null;
+ }
+ };
+ qq.isFolderDropSupported = function(dataTransfer) {
+ return dataTransfer.items && dataTransfer.items.length > 0 && dataTransfer.items[0].webkitGetAsEntry;
+ };
+ qq.isFileChunkingSupported = function() {
+ return !qq.androidStock() && qq.isXhrUploadSupported() && (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);
+ };
+ qq.sliceBlob = function(fileOrBlob, start, end) {
+ var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;
+ return slicer.call(fileOrBlob, start, end);
+ };
+ qq.arrayBufferToHex = function(buffer) {
+ var bytesAsHex = "", bytes = new Uint8Array(buffer);
+ qq.each(bytes, function(idx, byt) {
+ var byteAsHexStr = byt.toString(16);
+ if (byteAsHexStr.length < 2) {
+ byteAsHexStr = "0" + byteAsHexStr;
+ }
+ bytesAsHex += byteAsHexStr;
+ });
+ return bytesAsHex;
+ };
+ qq.readBlobToHex = function(blob, startOffset, length) {
+ var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), fileReader = new FileReader(), promise = new qq.Promise();
+ fileReader.onload = function() {
+ promise.success(qq.arrayBufferToHex(fileReader.result));
+ };
+ fileReader.onerror = promise.failure;
+ fileReader.readAsArrayBuffer(initialBlob);
+ return promise;
+ };
+ qq.extend = function(first, second, extendNested) {
+ qq.each(second, function(prop, val) {
+ if (extendNested && qq.isObject(val)) {
+ if (first[prop] === undefined) {
+ first[prop] = {};
+ }
+ qq.extend(first[prop], val, true);
+ } else {
+ first[prop] = val;
+ }
+ });
+ return first;
+ };
+ qq.override = function(target, sourceFn) {
+ var super_ = {}, source = sourceFn(super_);
+ qq.each(source, function(srcPropName, srcPropVal) {
+ if (target[srcPropName] !== undefined) {
+ super_[srcPropName] = target[srcPropName];
+ }
+ target[srcPropName] = srcPropVal;
+ });
+ return target;
+ };
+ qq.indexOf = function(arr, elt, from) {
+ if (arr.indexOf) {
+ return arr.indexOf(elt, from);
+ }
+ from = from || 0;
+ var len = arr.length;
+ if (from < 0) {
+ from += len;
+ }
+ for (;from < len; from += 1) {
+ if (arr.hasOwnProperty(from) && arr[from] === elt) {
+ return from;
+ }
+ }
+ return -1;
+ };
+ qq.getUniqueId = function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
+ return v.toString(16);
+ });
+ };
+ qq.ie = function() {
+ return navigator.userAgent.indexOf("MSIE") !== -1 || navigator.userAgent.indexOf("Trident") !== -1;
+ };
+ qq.ie7 = function() {
+ return navigator.userAgent.indexOf("MSIE 7") !== -1;
+ };
+ qq.ie8 = function() {
+ return navigator.userAgent.indexOf("MSIE 8") !== -1;
+ };
+ qq.ie10 = function() {
+ return navigator.userAgent.indexOf("MSIE 10") !== -1;
+ };
+ qq.ie11 = function() {
+ return qq.ie() && navigator.userAgent.indexOf("rv:11") !== -1;
+ };
+ qq.edge = function() {
+ return navigator.userAgent.indexOf("Edge") >= 0;
+ };
+ qq.safari = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Apple") !== -1;
+ };
+ qq.chrome = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Google") !== -1;
+ };
+ qq.opera = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Opera") !== -1;
+ };
+ qq.firefox = function() {
+ return !qq.edge() && !qq.ie11() && navigator.userAgent.indexOf("Mozilla") !== -1 && navigator.vendor !== undefined && navigator.vendor === "";
+ };
+ qq.windows = function() {
+ return navigator.platform === "Win32";
+ };
+ qq.android = function() {
+ return navigator.userAgent.toLowerCase().indexOf("android") !== -1;
+ };
+ qq.androidStock = function() {
+ return qq.android() && navigator.userAgent.toLowerCase().indexOf("chrome") < 0;
+ };
+ qq.ios6 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 6_") !== -1;
+ };
+ qq.ios7 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 7_") !== -1;
+ };
+ qq.ios8 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_") !== -1;
+ };
+ qq.ios800 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_0 ") !== -1;
+ };
+ qq.ios = function() {
+ return navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("iPod") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1;
+ };
+ qq.iosChrome = function() {
+ return qq.ios() && navigator.userAgent.indexOf("CriOS") !== -1;
+ };
+ qq.iosSafari = function() {
+ return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf("Safari") !== -1;
+ };
+ qq.iosSafariWebView = function() {
+ return qq.ios() && !qq.iosChrome() && !qq.iosSafari();
+ };
+ qq.preventDefault = function(e) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ };
+ qq.toElement = function() {
+ var div = document.createElement("div");
+ return function(html) {
+ div.innerHTML = html;
+ var element = div.firstChild;
+ div.removeChild(element);
+ return element;
+ };
+ }();
+ qq.each = function(iterableItem, callback) {
+ var keyOrIndex, retVal;
+ if (iterableItem) {
+ if (window.Storage && iterableItem.constructor === window.Storage) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isString(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else {
+ for (keyOrIndex in iterableItem) {
+ if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ };
+ qq.bind = function(oldFunc, context) {
+ if (qq.isFunction(oldFunc)) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ return function() {
+ var newArgs = qq.extend([], args);
+ if (arguments.length) {
+ newArgs = newArgs.concat(Array.prototype.slice.call(arguments));
+ }
+ return oldFunc.apply(context, newArgs);
+ };
+ }
+ throw new Error("first parameter must be a function!");
+ };
+ qq.obj2url = function(obj, temp, prefixDone) {
+ var uristrings = [], prefix = "&", add = function(nextObj, i) {
+ var nextTemp = temp ? /\[\]$/.test(temp) ? temp : temp + "[" + i + "]" : i;
+ if (nextTemp !== "undefined" && i !== "undefined") {
+ uristrings.push(typeof nextObj === "object" ? qq.obj2url(nextObj, nextTemp, true) : Object.prototype.toString.call(nextObj) === "[object Function]" ? encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj));
+ }
+ };
+ if (!prefixDone && temp) {
+ prefix = /\?/.test(temp) ? /\?$/.test(temp) ? "" : "&" : "?";
+ uristrings.push(temp);
+ uristrings.push(qq.obj2url(obj));
+ } else if (Object.prototype.toString.call(obj) === "[object Array]" && typeof obj !== "undefined") {
+ qq.each(obj, function(idx, val) {
+ add(val, idx);
+ });
+ } else if (typeof obj !== "undefined" && obj !== null && typeof obj === "object") {
+ qq.each(obj, function(prop, val) {
+ add(val, prop);
+ });
+ } else {
+ uristrings.push(encodeURIComponent(temp) + "=" + encodeURIComponent(obj));
+ }
+ if (temp) {
+ return uristrings.join(prefix);
+ } else {
+ return uristrings.join(prefix).replace(/^&/, "").replace(/%20/g, "+");
+ }
+ };
+ qq.obj2FormData = function(obj, formData, arrayKeyName) {
+ if (!formData) {
+ formData = new FormData();
+ }
+ qq.each(obj, function(key, val) {
+ key = arrayKeyName ? arrayKeyName + "[" + key + "]" : key;
+ if (qq.isObject(val)) {
+ qq.obj2FormData(val, formData, key);
+ } else if (qq.isFunction(val)) {
+ formData.append(key, val());
+ } else {
+ formData.append(key, val);
+ }
+ });
+ return formData;
+ };
+ qq.obj2Inputs = function(obj, form) {
+ var input;
+ if (!form) {
+ form = document.createElement("form");
+ }
+ qq.obj2FormData(obj, {
+ append: function(key, val) {
+ input = document.createElement("input");
+ input.setAttribute("name", key);
+ input.setAttribute("value", val);
+ form.appendChild(input);
+ }
+ });
+ return form;
+ };
+ qq.parseJson = function(json) {
+ if (window.JSON && qq.isFunction(JSON.parse)) {
+ return JSON.parse(json);
+ } else {
+ return eval("(" + json + ")");
+ }
+ };
+ qq.getExtension = function(filename) {
+ var extIdx = filename.lastIndexOf(".") + 1;
+ if (extIdx > 0) {
+ return filename.substr(extIdx, filename.length - extIdx);
+ }
+ };
+ qq.getFilename = function(blobOrFileInput) {
+ if (qq.isInput(blobOrFileInput)) {
+ return blobOrFileInput.value.replace(/.*(\/|\\)/, "");
+ } else if (qq.isFile(blobOrFileInput)) {
+ if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {
+ return blobOrFileInput.fileName;
+ }
+ }
+ return blobOrFileInput.name;
+ };
+ qq.DisposeSupport = function() {
+ var disposers = [];
+ return {
+ dispose: function() {
+ var disposer;
+ do {
+ disposer = disposers.shift();
+ if (disposer) {
+ disposer();
+ }
+ } while (disposer);
+ },
+ attach: function() {
+ var args = arguments;
+ this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));
+ },
+ addDisposer: function(disposeFunction) {
+ disposers.push(disposeFunction);
+ }
+ };
+ };
+ })();
+ (function() {
+ "use strict";
+ if (typeof define === "function" && define.amd) {
+ define(function() {
+ return qq;
+ });
+ } else if (typeof module !== "undefined" && module.exports) {
+ module.exports = qq;
+ } else {
+ global.qq = qq;
+ }
+ })();
+ (function() {
+ "use strict";
+ qq.Error = function(message) {
+ this.message = "[Fine Uploader " + qq.version + "] " + message;
+ };
+ qq.Error.prototype = new Error();
+ })();
+ qq.version = "5.13.0";
+ qq.supportedFeatures = function() {
+ "use strict";
+ var supportsUploading, supportsUploadingBlobs, supportsFileDrop, supportsAjaxFileUploading, supportsFolderDrop, supportsChunking, supportsResume, supportsUploadViaPaste, supportsUploadCors, supportsDeleteFileXdr, supportsDeleteFileCorsXhr, supportsDeleteFileCors, supportsFolderSelection, supportsImagePreviews, supportsUploadProgress;
+ function testSupportsFileInputElement() {
+ var supported = true, tempInput;
+ try {
+ tempInput = document.createElement("input");
+ tempInput.type = "file";
+ qq(tempInput).hide();
+ if (tempInput.disabled) {
+ supported = false;
+ }
+ } catch (ex) {
+ supported = false;
+ }
+ return supported;
+ }
+ function isChrome21OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/) !== undefined;
+ }
+ function isChrome14OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/) !== undefined;
+ }
+ function isCrossOriginXhrSupported() {
+ if (window.XMLHttpRequest) {
+ var xhr = qq.createXhrInstance();
+ return xhr.withCredentials !== undefined;
+ }
+ return false;
+ }
+ function isXdrSupported() {
+ return window.XDomainRequest !== undefined;
+ }
+ function isCrossOriginAjaxSupported() {
+ if (isCrossOriginXhrSupported()) {
+ return true;
+ }
+ return isXdrSupported();
+ }
+ function isFolderSelectionSupported() {
+ return document.createElement("input").webkitdirectory !== undefined;
+ }
+ function isLocalStorageSupported() {
+ try {
+ return !!window.localStorage && qq.isFunction(window.localStorage.setItem);
+ } catch (error) {
+ return false;
+ }
+ }
+ function isDragAndDropSupported() {
+ var span = document.createElement("span");
+ return ("draggable" in span || "ondragstart" in span && "ondrop" in span) && !qq.android() && !qq.ios();
+ }
+ supportsUploading = testSupportsFileInputElement();
+ supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();
+ supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();
+ supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();
+ supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();
+ supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();
+ supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();
+ supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();
+ supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);
+ supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();
+ supportsDeleteFileXdr = isXdrSupported();
+ supportsDeleteFileCors = isCrossOriginAjaxSupported();
+ supportsFolderSelection = isFolderSelectionSupported();
+ supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;
+ supportsUploadProgress = function() {
+ if (supportsAjaxFileUploading) {
+ return !qq.androidStock() && !qq.iosChrome();
+ }
+ return false;
+ }();
+ return {
+ ajaxUploading: supportsAjaxFileUploading,
+ blobUploading: supportsUploadingBlobs,
+ canDetermineSize: supportsAjaxFileUploading,
+ chunking: supportsChunking,
+ deleteFileCors: supportsDeleteFileCors,
+ deleteFileCorsXdr: supportsDeleteFileXdr,
+ deleteFileCorsXhr: supportsDeleteFileCorsXhr,
+ dialogElement: !!window.HTMLDialogElement,
+ fileDrop: supportsFileDrop,
+ folderDrop: supportsFolderDrop,
+ folderSelection: supportsFolderSelection,
+ imagePreviews: supportsImagePreviews,
+ imageValidation: supportsImagePreviews,
+ itemSizeValidation: supportsAjaxFileUploading,
+ pause: supportsChunking,
+ progressBar: supportsUploadProgress,
+ resume: supportsResume,
+ scaling: supportsImagePreviews && supportsUploadingBlobs,
+ tiffPreviews: qq.safari(),
+ unlimitedScaledImageSize: !qq.ios(),
+ uploading: supportsUploading,
+ uploadCors: supportsUploadCors,
+ uploadCustomHeaders: supportsAjaxFileUploading,
+ uploadNonMultipart: supportsAjaxFileUploading,
+ uploadViaPaste: supportsUploadViaPaste
+ };
+ }();
+ qq.isGenericPromise = function(maybePromise) {
+ "use strict";
+ return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));
+ };
+ qq.Promise = function() {
+ "use strict";
+ var successArgs, failureArgs, successCallbacks = [], failureCallbacks = [], doneCallbacks = [], state = 0;
+ qq.extend(this, {
+ then: function(onSuccess, onFailure) {
+ if (state === 0) {
+ if (onSuccess) {
+ successCallbacks.push(onSuccess);
+ }
+ if (onFailure) {
+ failureCallbacks.push(onFailure);
+ }
+ } else if (state === -1) {
+ onFailure && onFailure.apply(null, failureArgs);
+ } else if (onSuccess) {
+ onSuccess.apply(null, successArgs);
+ }
+ return this;
+ },
+ done: function(callback) {
+ if (state === 0) {
+ doneCallbacks.push(callback);
+ } else {
+ callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);
+ }
+ return this;
+ },
+ success: function() {
+ state = 1;
+ successArgs = arguments;
+ if (successCallbacks.length) {
+ qq.each(successCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ return this;
+ },
+ failure: function() {
+ state = -1;
+ failureArgs = arguments;
+ if (failureCallbacks.length) {
+ qq.each(failureCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ return this;
+ }
+ });
+ };
+ qq.BlobProxy = function(referenceBlob, onCreate) {
+ "use strict";
+ qq.extend(this, {
+ referenceBlob: referenceBlob,
+ create: function() {
+ return onCreate(referenceBlob);
+ }
+ });
+ };
+ qq.UploadButton = function(o) {
+ "use strict";
+ var self = this, disposeSupport = new qq.DisposeSupport(), options = {
+ acceptFiles: null,
+ element: null,
+ focusClass: "qq-upload-button-focus",
+ folders: false,
+ hoverClass: "qq-upload-button-hover",
+ ios8BrowserCrashWorkaround: false,
+ multiple: false,
+ name: "qqfile",
+ onChange: function(input) {},
+ title: null
+ }, input, buttonId;
+ qq.extend(options, o);
+ buttonId = qq.getUniqueId();
+ function createInput() {
+ var input = document.createElement("input");
+ input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);
+ input.setAttribute("title", options.title);
+ self.setMultiple(options.multiple, input);
+ if (options.folders && qq.supportedFeatures.folderSelection) {
+ input.setAttribute("webkitdirectory", "");
+ }
+ if (options.acceptFiles) {
+ input.setAttribute("accept", options.acceptFiles);
+ }
+ input.setAttribute("type", "file");
+ input.setAttribute("name", options.name);
+ qq(input).css({
+ position: "absolute",
+ right: 0,
+ top: 0,
+ fontFamily: "Arial",
+ fontSize: qq.ie() && !qq.ie8() ? "3500px" : "118px",
+ margin: 0,
+ padding: 0,
+ cursor: "pointer",
+ opacity: 0
+ });
+ !qq.ie7() && qq(input).css({
+ height: "100%"
+ });
+ options.element.appendChild(input);
+ disposeSupport.attach(input, "change", function() {
+ options.onChange(input);
+ });
+ disposeSupport.attach(input, "mouseover", function() {
+ qq(options.element).addClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "mouseout", function() {
+ qq(options.element).removeClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "focus", function() {
+ qq(options.element).addClass(options.focusClass);
+ });
+ disposeSupport.attach(input, "blur", function() {
+ qq(options.element).removeClass(options.focusClass);
+ });
+ return input;
+ }
+ qq(options.element).css({
+ position: "relative",
+ overflow: "hidden",
+ direction: "ltr"
+ });
+ qq.extend(this, {
+ getInput: function() {
+ return input;
+ },
+ getButtonId: function() {
+ return buttonId;
+ },
+ setMultiple: function(isMultiple, optInput) {
+ var input = optInput || this.getInput();
+ if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {
+ input.setAttribute("multiple", "");
+ } else {
+ if (isMultiple) {
+ input.setAttribute("multiple", "");
+ } else {
+ input.removeAttribute("multiple");
+ }
+ }
+ },
+ setAcceptFiles: function(acceptFiles) {
+ if (acceptFiles !== options.acceptFiles) {
+ input.setAttribute("accept", acceptFiles);
+ }
+ },
+ reset: function() {
+ if (input.parentNode) {
+ qq(input).remove();
+ }
+ qq(options.element).removeClass(options.focusClass);
+ input = null;
+ input = createInput();
+ }
+ });
+ input = createInput();
+ };
+ qq.UploadButton.BUTTON_ID_ATTR_NAME = "qq-button-id";
+ qq.UploadData = function(uploaderProxy) {
+ "use strict";
+ var data = [], byUuid = {}, byStatus = {}, byProxyGroupId = {}, byBatchId = {};
+ function getDataByIds(idOrIds) {
+ if (qq.isArray(idOrIds)) {
+ var entries = [];
+ qq.each(idOrIds, function(idx, id) {
+ entries.push(data[id]);
+ });
+ return entries;
+ }
+ return data[idOrIds];
+ }
+ function getDataByUuids(uuids) {
+ if (qq.isArray(uuids)) {
+ var entries = [];
+ qq.each(uuids, function(idx, uuid) {
+ entries.push(data[byUuid[uuid]]);
+ });
+ return entries;
+ }
+ return data[byUuid[uuids]];
+ }
+ function getDataByStatus(status) {
+ var statusResults = [], statuses = [].concat(status);
+ qq.each(statuses, function(index, statusEnum) {
+ var statusResultIndexes = byStatus[statusEnum];
+ if (statusResultIndexes !== undefined) {
+ qq.each(statusResultIndexes, function(i, dataIndex) {
+ statusResults.push(data[dataIndex]);
+ });
+ }
+ });
+ return statusResults;
+ }
+ qq.extend(this, {
+ addFile: function(spec) {
+ var status = spec.status || qq.status.SUBMITTING, id = data.push({
+ name: spec.name,
+ originalName: spec.name,
+ uuid: spec.uuid,
+ size: spec.size == null ? -1 : spec.size,
+ status: status
+ }) - 1;
+ if (spec.batchId) {
+ data[id].batchId = spec.batchId;
+ if (byBatchId[spec.batchId] === undefined) {
+ byBatchId[spec.batchId] = [];
+ }
+ byBatchId[spec.batchId].push(id);
+ }
+ if (spec.proxyGroupId) {
+ data[id].proxyGroupId = spec.proxyGroupId;
+ if (byProxyGroupId[spec.proxyGroupId] === undefined) {
+ byProxyGroupId[spec.proxyGroupId] = [];
+ }
+ byProxyGroupId[spec.proxyGroupId].push(id);
+ }
+ data[id].id = id;
+ byUuid[spec.uuid] = id;
+ if (byStatus[status] === undefined) {
+ byStatus[status] = [];
+ }
+ byStatus[status].push(id);
+ uploaderProxy.onStatusChange(id, null, status);
+ return id;
+ },
+ retrieve: function(optionalFilter) {
+ if (qq.isObject(optionalFilter) && data.length) {
+ if (optionalFilter.id !== undefined) {
+ return getDataByIds(optionalFilter.id);
+ } else if (optionalFilter.uuid !== undefined) {
+ return getDataByUuids(optionalFilter.uuid);
+ } else if (optionalFilter.status) {
+ return getDataByStatus(optionalFilter.status);
+ }
+ } else {
+ return qq.extend([], data, true);
+ }
+ },
+ reset: function() {
+ data = [];
+ byUuid = {};
+ byStatus = {};
+ byBatchId = {};
+ },
+ setStatus: function(id, newStatus) {
+ var oldStatus = data[id].status, byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);
+ byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);
+ data[id].status = newStatus;
+ if (byStatus[newStatus] === undefined) {
+ byStatus[newStatus] = [];
+ }
+ byStatus[newStatus].push(id);
+ uploaderProxy.onStatusChange(id, oldStatus, newStatus);
+ },
+ uuidChanged: function(id, newUuid) {
+ var oldUuid = data[id].uuid;
+ data[id].uuid = newUuid;
+ byUuid[newUuid] = id;
+ delete byUuid[oldUuid];
+ },
+ updateName: function(id, newName) {
+ data[id].name = newName;
+ },
+ updateSize: function(id, newSize) {
+ data[id].size = newSize;
+ },
+ setParentId: function(targetId, parentId) {
+ data[targetId].parentId = parentId;
+ },
+ getIdsInProxyGroup: function(id) {
+ var proxyGroupId = data[id].proxyGroupId;
+ if (proxyGroupId) {
+ return byProxyGroupId[proxyGroupId];
+ }
+ return [];
+ },
+ getIdsInBatch: function(id) {
+ var batchId = data[id].batchId;
+ return byBatchId[batchId];
+ }
+ });
+ };
+ qq.status = {
+ SUBMITTING: "submitting",
+ SUBMITTED: "submitted",
+ REJECTED: "rejected",
+ QUEUED: "queued",
+ CANCELED: "canceled",
+ PAUSED: "paused",
+ UPLOADING: "uploading",
+ UPLOAD_RETRYING: "retrying upload",
+ UPLOAD_SUCCESSFUL: "upload successful",
+ UPLOAD_FAILED: "upload failed",
+ DELETE_FAILED: "delete failed",
+ DELETING: "deleting",
+ DELETED: "deleted"
+ };
+ (function() {
+ "use strict";
+ qq.basePublicApi = {
+ addBlobs: function(blobDataOrArray, params, endpoint) {
+ this.addFiles(blobDataOrArray, params, endpoint);
+ },
+ addInitialFiles: function(cannedFileList) {
+ var self = this;
+ qq.each(cannedFileList, function(index, cannedFile) {
+ self._addCannedFile(cannedFile);
+ });
+ },
+ addFiles: function(data, params, endpoint) {
+ this._maybeHandleIos8SafariWorkaround();
+ var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId, processBlob = qq.bind(function(blob) {
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName
+ }, batchId, verifiedFiles);
+ }, this), processBlobData = qq.bind(function(blobData) {
+ this._handleNewFile(blobData, batchId, verifiedFiles);
+ }, this), processCanvas = qq.bind(function(canvas) {
+ var blob = qq.canvasToBlob(canvas);
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName + ".png"
+ }, batchId, verifiedFiles);
+ }, this), processCanvasData = qq.bind(function(canvasData) {
+ var normalizedQuality = canvasData.quality && canvasData.quality / 100, blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);
+ this._handleNewFile({
+ blob: blob,
+ name: canvasData.name
+ }, batchId, verifiedFiles);
+ }, this), processFileOrInput = qq.bind(function(fileOrInput) {
+ if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {
+ var files = Array.prototype.slice.call(fileOrInput.files), self = this;
+ qq.each(files, function(idx, file) {
+ self._handleNewFile(file, batchId, verifiedFiles);
+ });
+ } else {
+ this._handleNewFile(fileOrInput, batchId, verifiedFiles);
+ }
+ }, this), normalizeData = function() {
+ if (qq.isFileList(data)) {
+ data = Array.prototype.slice.call(data);
+ }
+ data = [].concat(data);
+ }, self = this, verifiedFiles = [];
+ this._currentBatchId = batchId;
+ if (data) {
+ normalizeData();
+ qq.each(data, function(idx, fileContainer) {
+ if (qq.isFileOrInput(fileContainer)) {
+ processFileOrInput(fileContainer);
+ } else if (qq.isBlob(fileContainer)) {
+ processBlob(fileContainer);
+ } else if (qq.isObject(fileContainer)) {
+ if (fileContainer.blob && fileContainer.name) {
+ processBlobData(fileContainer);
+ } else if (fileContainer.canvas && fileContainer.name) {
+ processCanvasData(fileContainer);
+ }
+ } else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === "canvas") {
+ processCanvas(fileContainer);
+ } else {
+ self.log(fileContainer + " is not a valid file container! Ignoring!", "warn");
+ }
+ });
+ this.log("Received " + verifiedFiles.length + " files.");
+ this._prepareItemsForUpload(verifiedFiles, params, endpoint);
+ }
+ },
+ cancel: function(id) {
+ this._handler.cancel(id);
+ },
+ cancelAll: function() {
+ var storedIdsCopy = [], self = this;
+ qq.extend(storedIdsCopy, this._storedIds);
+ qq.each(storedIdsCopy, function(idx, storedFileId) {
+ self.cancel(storedFileId);
+ });
+ this._handler.cancelAll();
+ },
+ clearStoredFiles: function() {
+ this._storedIds = [];
+ },
+ continueUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (uploadData.status === qq.status.PAUSED) {
+ this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.", id, this.getName(id)));
+ this._uploadFile(id);
+ return true;
+ } else {
+ this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ deleteFile: function(id) {
+ return this._onSubmitDelete(id);
+ },
+ doesExist: function(fileOrBlobId) {
+ return this._handler.isValid(fileOrBlobId);
+ },
+ drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {
+ var promiseToReturn = new qq.Promise(), fileOrUrl, options;
+ if (this._imageGenerator) {
+ fileOrUrl = this._thumbnailUrls[fileId];
+ options = {
+ customResizeFunction: customResizeFunction,
+ maxSize: maxSize > 0 ? maxSize : null,
+ scale: maxSize > 0
+ };
+ if (!fromServer && qq.supportedFeatures.imagePreviews) {
+ fileOrUrl = this.getFile(fileId);
+ }
+ if (fileOrUrl == null) {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "File or URL not found."
+ });
+ } else {
+ this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(function success(modifiedContainer) {
+ promiseToReturn.success(modifiedContainer);
+ }, function failure(container, reason) {
+ promiseToReturn.failure({
+ container: container,
+ error: reason || "Problem generating thumbnail"
+ });
+ });
+ }
+ } else {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "Missing image generator module"
+ });
+ }
+ return promiseToReturn;
+ },
+ getButton: function(fileId) {
+ return this._getButton(this._buttonIdsForFileIds[fileId]);
+ },
+ getEndpoint: function(fileId) {
+ return this._endpointStore.get(fileId);
+ },
+ getFile: function(fileOrBlobId) {
+ return this._handler.getFile(fileOrBlobId) || null;
+ },
+ getInProgress: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED ]
+ }).length;
+ },
+ getName: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).name;
+ },
+ getParentId: function(id) {
+ var uploadDataEntry = this.getUploads({
+ id: id
+ }), parentId = null;
+ if (uploadDataEntry) {
+ if (uploadDataEntry.parentId !== undefined) {
+ parentId = uploadDataEntry.parentId;
+ }
+ }
+ return parentId;
+ },
+ getResumableFilesData: function() {
+ return this._handler.getResumableFilesData();
+ },
+ getSize: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).size;
+ },
+ getNetUploads: function() {
+ return this._netUploaded;
+ },
+ getRemainingAllowedItems: function() {
+ var allowedItems = this._currentItemLimit;
+ if (allowedItems > 0) {
+ return allowedItems - this._netUploadedOrQueued;
+ }
+ return null;
+ },
+ getUploads: function(optionalFilter) {
+ return this._uploadData.retrieve(optionalFilter);
+ },
+ getUuid: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).uuid;
+ },
+ log: function(str, level) {
+ if (this._options.debug && (!level || level === "info")) {
+ qq.log("[Fine Uploader " + qq.version + "] " + str);
+ } else if (level && level !== "info") {
+ qq.log("[Fine Uploader " + qq.version + "] " + str, level);
+ }
+ },
+ pauseUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (qq.indexOf([ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING ], uploadData.status) >= 0) {
+ if (this._handler.pause(id)) {
+ this._uploadData.setStatus(id, qq.status.PAUSED);
+ return true;
+ } else {
+ this.log(qq.format("Unable to pause file ID {} ({}).", id, this.getName(id)), "error");
+ }
+ } else {
+ this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ reset: function() {
+ this.log("Resetting uploader...");
+ this._handler.reset();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ this._paramsStore.reset();
+ this._endpointStore.reset();
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData.reset();
+ this._buttonIdsForFileIds = [];
+ this._pasteHandler && this._pasteHandler.reset();
+ this._options.session.refreshOnReset && this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._totalProgress && this._totalProgress.reset();
+ },
+ retry: function(id) {
+ return this._manualRetry(id);
+ },
+ scaleImage: function(id, specs) {
+ var self = this;
+ return qq.Scaler.prototype.scaleImage(id, specs, {
+ log: qq.bind(self.log, self),
+ getFile: qq.bind(self.getFile, self),
+ uploadData: self._uploadData
+ });
+ },
+ setCustomHeaders: function(headers, id) {
+ this._customHeadersStore.set(headers, id);
+ },
+ setDeleteFileCustomHeaders: function(headers, id) {
+ this._deleteFileCustomHeadersStore.set(headers, id);
+ },
+ setDeleteFileEndpoint: function(endpoint, id) {
+ this._deleteFileEndpointStore.set(endpoint, id);
+ },
+ setDeleteFileParams: function(params, id) {
+ this._deleteFileParamsStore.set(params, id);
+ },
+ setEndpoint: function(endpoint, id) {
+ this._endpointStore.set(endpoint, id);
+ },
+ setForm: function(elementOrId) {
+ this._updateFormSupportAndParams(elementOrId);
+ },
+ setItemLimit: function(newItemLimit) {
+ this._currentItemLimit = newItemLimit;
+ },
+ setName: function(id, newName) {
+ this._uploadData.updateName(id, newName);
+ },
+ setParams: function(params, id) {
+ this._paramsStore.set(params, id);
+ },
+ setUuid: function(id, newUuid) {
+ return this._uploadData.uuidChanged(id, newUuid);
+ },
+ uploadStoredFiles: function() {
+ if (this._storedIds.length === 0) {
+ this._itemError("noFilesError");
+ } else {
+ this._uploadStoredFiles();
+ }
+ }
+ };
+ qq.basePrivateApi = {
+ _addCannedFile: function(sessionData) {
+ var id = this._uploadData.addFile({
+ uuid: sessionData.uuid,
+ name: sessionData.name,
+ size: sessionData.size,
+ status: qq.status.UPLOAD_SUCCESSFUL
+ });
+ sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);
+ sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);
+ if (sessionData.thumbnailUrl) {
+ this._thumbnailUrls[id] = sessionData.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._netUploadedOrQueued++;
+ return id;
+ },
+ _annotateWithButtonId: function(file, associatedInput) {
+ if (qq.isFile(file)) {
+ file.qqButtonId = this._getButtonId(associatedInput);
+ }
+ },
+ _batchError: function(message) {
+ this._options.callbacks.onError(null, null, message, undefined);
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return new qq.DeleteFileAjaxRequester({
+ method: this._options.deleteFile.method.toUpperCase(),
+ maxConnections: this._options.maxConnections,
+ uuidParamName: this._options.request.uuidName,
+ customHeaders: this._deleteFileCustomHeadersStore,
+ paramsStore: this._deleteFileParamsStore,
+ endpointStore: this._deleteFileEndpointStore,
+ cors: this._options.cors,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ });
+ },
+ _createPasteHandler: function() {
+ var self = this;
+ return new qq.PasteSupport({
+ targetElement: this._options.paste.targetElement,
+ callbacks: {
+ log: qq.bind(self.log, self),
+ pasteReceived: function(blob) {
+ self._handleCheckedCallback({
+ name: "onPasteReceived",
+ callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),
+ onSuccess: qq.bind(self._handlePasteSuccess, self, blob),
+ identifier: "pasted image"
+ });
+ }
+ }
+ });
+ },
+ _createStore: function(initialValue, _readOnlyValues_) {
+ var store = {}, catchall = initialValue, perIdReadOnlyValues = {}, readOnlyValues = _readOnlyValues_, copy = function(orig) {
+ if (qq.isObject(orig)) {
+ return qq.extend({}, orig);
+ }
+ return orig;
+ }, getReadOnlyValues = function() {
+ if (qq.isFunction(readOnlyValues)) {
+ return readOnlyValues();
+ }
+ return readOnlyValues;
+ }, includeReadOnlyValues = function(id, existing) {
+ if (readOnlyValues && qq.isObject(existing)) {
+ qq.extend(existing, getReadOnlyValues());
+ }
+ if (perIdReadOnlyValues[id]) {
+ qq.extend(existing, perIdReadOnlyValues[id]);
+ }
+ };
+ return {
+ set: function(val, id) {
+ if (id == null) {
+ store = {};
+ catchall = copy(val);
+ } else {
+ store[id] = copy(val);
+ }
+ },
+ get: function(id) {
+ var values;
+ if (id != null && store[id]) {
+ values = store[id];
+ } else {
+ values = copy(catchall);
+ }
+ includeReadOnlyValues(id, values);
+ return copy(values);
+ },
+ addReadOnly: function(id, values) {
+ if (qq.isObject(store)) {
+ if (id === null) {
+ if (qq.isFunction(values)) {
+ readOnlyValues = values;
+ } else {
+ readOnlyValues = readOnlyValues || {};
+ qq.extend(readOnlyValues, values);
+ }
+ } else {
+ perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};
+ qq.extend(perIdReadOnlyValues[id], values);
+ }
+ }
+ },
+ remove: function(fileId) {
+ return delete store[fileId];
+ },
+ reset: function() {
+ store = {};
+ perIdReadOnlyValues = {};
+ catchall = initialValue;
+ }
+ };
+ },
+ _createUploadDataTracker: function() {
+ var self = this;
+ return new qq.UploadData({
+ getName: function(id) {
+ return self.getName(id);
+ },
+ getUuid: function(id) {
+ return self.getUuid(id);
+ },
+ getSize: function(id) {
+ return self.getSize(id);
+ },
+ onStatusChange: function(id, oldStatus, newStatus) {
+ self._onUploadStatusChange(id, oldStatus, newStatus);
+ self._options.callbacks.onStatusChange(id, oldStatus, newStatus);
+ self._maybeAllComplete(id, newStatus);
+ if (self._totalProgress) {
+ setTimeout(function() {
+ self._totalProgress.onStatusChange(id, oldStatus, newStatus);
+ }, 0);
+ }
+ }
+ });
+ },
+ _createUploadButton: function(spec) {
+ var self = this, acceptFiles = spec.accept || this._options.validation.acceptFiles, allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions, button;
+ function allowMultiple() {
+ if (qq.supportedFeatures.ajaxUploading) {
+ if (self._options.workarounds.iosEmptyVideos && qq.ios() && !qq.ios6() && self._isAllowedExtension(allowedExtensions, ".mov")) {
+ return false;
+ }
+ if (spec.multiple === undefined) {
+ return self._options.multiple;
+ }
+ return spec.multiple;
+ }
+ return false;
+ }
+ button = new qq.UploadButton({
+ acceptFiles: acceptFiles,
+ element: spec.element,
+ focusClass: this._options.classes.buttonFocus,
+ folders: spec.folders,
+ hoverClass: this._options.classes.buttonHover,
+ ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,
+ multiple: allowMultiple(),
+ name: this._options.request.inputName,
+ onChange: function(input) {
+ self._onInputChange(input);
+ },
+ title: spec.title == null ? this._options.text.fileInputTitle : spec.title
+ });
+ this._disposeSupport.addDisposer(function() {
+ button.dispose();
+ });
+ self._buttons.push(button);
+ return button;
+ },
+ _createUploadHandler: function(additionalOptions, namespace) {
+ var self = this, lastOnProgress = {}, options = {
+ debug: this._options.debug,
+ maxConnections: this._options.maxConnections,
+ cors: this._options.cors,
+ paramsStore: this._paramsStore,
+ endpointStore: this._endpointStore,
+ chunking: this._options.chunking,
+ resume: this._options.resume,
+ blobs: this._options.blobs,
+ log: qq.bind(self.log, self),
+ preventRetryParam: this._options.retry.preventRetryResponseProperty,
+ onProgress: function(id, name, loaded, total) {
+ if (loaded < 0 || total < 0) {
+ return;
+ }
+ if (lastOnProgress[id]) {
+ if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ } else {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ lastOnProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onComplete: function(id, name, result, xhr) {
+ delete lastOnProgress[id];
+ var status = self.getUploads({
+ id: id
+ }).status, retVal;
+ if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {
+ return;
+ }
+ retVal = self._onComplete(id, name, result, xhr);
+ if (retVal instanceof qq.Promise) {
+ retVal.done(function() {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ });
+ } else {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ }
+ },
+ onCancel: function(id, name, cancelFinalizationEffort) {
+ var promise = new qq.Promise();
+ self._handleCheckedCallback({
+ name: "onCancel",
+ callback: qq.bind(self._options.callbacks.onCancel, self, id, name),
+ onFailure: promise.failure,
+ onSuccess: function() {
+ cancelFinalizationEffort.then(function() {
+ self._onCancel(id, name);
+ });
+ promise.success();
+ },
+ identifier: id
+ });
+ return promise;
+ },
+ onUploadPrep: qq.bind(this._onUploadPrep, this),
+ onUpload: function(id, name) {
+ self._onUpload(id, name);
+ self._options.callbacks.onUpload(id, name);
+ },
+ onUploadChunk: function(id, name, chunkData) {
+ self._onUploadChunk(id, chunkData);
+ self._options.callbacks.onUploadChunk(id, name, chunkData);
+ },
+ onUploadChunkSuccess: function(id, chunkData, result, xhr) {
+ self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);
+ },
+ onResume: function(id, name, chunkData) {
+ return self._options.callbacks.onResume(id, name, chunkData);
+ },
+ onAutoRetry: function(id, name, responseJSON, xhr) {
+ return self._onAutoRetry.apply(self, arguments);
+ },
+ onUuidChanged: function(id, newUuid) {
+ self.log("Server requested UUID change from '" + self.getUuid(id) + "' to '" + newUuid + "'");
+ self.setUuid(id, newUuid);
+ },
+ getName: qq.bind(self.getName, self),
+ getUuid: qq.bind(self.getUuid, self),
+ getSize: qq.bind(self.getSize, self),
+ setSize: qq.bind(self._setSize, self),
+ getDataByUuid: function(uuid) {
+ return self.getUploads({
+ uuid: uuid
+ });
+ },
+ isQueued: function(id) {
+ var status = self.getUploads({
+ id: id
+ }).status;
+ return status === qq.status.QUEUED || status === qq.status.SUBMITTED || status === qq.status.UPLOAD_RETRYING || status === qq.status.PAUSED;
+ },
+ getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,
+ getIdsInBatch: self._uploadData.getIdsInBatch
+ };
+ qq.each(this._options.request, function(prop, val) {
+ options[prop] = val;
+ });
+ options.customHeaders = this._customHeadersStore;
+ if (additionalOptions) {
+ qq.each(additionalOptions, function(key, val) {
+ options[key] = val;
+ });
+ }
+ return new qq.UploadHandlerController(options, namespace);
+ },
+ _fileOrBlobRejected: function(id) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.REJECTED);
+ },
+ _formatSize: function(bytes) {
+ if (bytes === 0) {
+ return bytes + this._options.text.sizeSymbols[0];
+ }
+ var i = -1;
+ do {
+ bytes = bytes / 1e3;
+ i++;
+ } while (bytes > 999);
+ return Math.max(bytes, .1).toFixed(1) + this._options.text.sizeSymbols[i];
+ },
+ _generateExtraButtonSpecs: function() {
+ var self = this;
+ this._extraButtonSpecs = {};
+ qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {
+ var multiple = extraButtonOptionEntry.multiple, validation = qq.extend({}, self._options.validation, true), extraButtonSpec = qq.extend({}, extraButtonOptionEntry);
+ if (multiple === undefined) {
+ multiple = self._options.multiple;
+ }
+ if (extraButtonSpec.validation) {
+ qq.extend(validation, extraButtonOptionEntry.validation, true);
+ }
+ qq.extend(extraButtonSpec, {
+ multiple: multiple,
+ validation: validation
+ }, true);
+ self._initExtraButton(extraButtonSpec);
+ });
+ },
+ _getButton: function(buttonId) {
+ var extraButtonsSpec = this._extraButtonSpecs[buttonId];
+ if (extraButtonsSpec) {
+ return extraButtonsSpec.element;
+ } else if (buttonId === this._defaultButtonId) {
+ return this._options.button;
+ }
+ },
+ _getButtonId: function(buttonOrFileInputOrFile) {
+ var inputs, fileInput, fileBlobOrInput = buttonOrFileInputOrFile;
+ if (fileBlobOrInput instanceof qq.BlobProxy) {
+ fileBlobOrInput = fileBlobOrInput.referenceBlob;
+ }
+ if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {
+ if (qq.isFile(fileBlobOrInput)) {
+ return fileBlobOrInput.qqButtonId;
+ } else if (fileBlobOrInput.tagName.toLowerCase() === "input" && fileBlobOrInput.type.toLowerCase() === "file") {
+ return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ inputs = fileBlobOrInput.getElementsByTagName("input");
+ qq.each(inputs, function(idx, input) {
+ if (input.getAttribute("type") === "file") {
+ fileInput = input;
+ return false;
+ }
+ });
+ if (fileInput) {
+ return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ }
+ },
+ _getNotFinished: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED, qq.status.SUBMITTING, qq.status.SUBMITTED, qq.status.PAUSED ]
+ }).length;
+ },
+ _getValidationBase: function(buttonId) {
+ var extraButtonSpec = this._extraButtonSpecs[buttonId];
+ return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;
+ },
+ _getValidationDescriptor: function(fileWrapper) {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return {
+ name: qq.getFilename(fileWrapper.file.referenceBlob),
+ size: fileWrapper.file.referenceBlob.size
+ };
+ }
+ return {
+ name: this.getUploads({
+ id: fileWrapper.id
+ }).name,
+ size: this.getUploads({
+ id: fileWrapper.id
+ }).size
+ };
+ },
+ _getValidationDescriptors: function(fileWrappers) {
+ var self = this, fileDescriptors = [];
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ fileDescriptors.push(self._getValidationDescriptor(fileWrapper));
+ });
+ return fileDescriptors;
+ },
+ _handleCameraAccess: function() {
+ if (this._options.camera.ios && qq.ios()) {
+ var acceptIosCamera = "image/*;capture=camera", button = this._options.camera.button, buttonId = button ? this._getButtonId(button) : this._defaultButtonId, optionRoot = this._options;
+ if (buttonId && buttonId !== this._defaultButtonId) {
+ optionRoot = this._extraButtonSpecs[buttonId];
+ }
+ optionRoot.multiple = false;
+ if (optionRoot.validation.acceptFiles === null) {
+ optionRoot.validation.acceptFiles = acceptIosCamera;
+ } else {
+ optionRoot.validation.acceptFiles += "," + acceptIosCamera;
+ }
+ qq.each(this._buttons, function(idx, button) {
+ if (button.getButtonId() === buttonId) {
+ button.setMultiple(optionRoot.multiple);
+ button.setAcceptFiles(optionRoot.acceptFiles);
+ return false;
+ }
+ });
+ }
+ },
+ _handleCheckedCallback: function(details) {
+ var self = this, callbackRetVal = details.callback();
+ if (qq.isGenericPromise(callbackRetVal)) {
+ this.log(details.name + " - waiting for " + details.name + " promise to be fulfilled for " + details.identifier);
+ return callbackRetVal.then(function(successParam) {
+ self.log(details.name + " promise success for " + details.identifier);
+ details.onSuccess(successParam);
+ }, function() {
+ if (details.onFailure) {
+ self.log(details.name + " promise failure for " + details.identifier);
+ details.onFailure();
+ } else {
+ self.log(details.name + " promise failure for " + details.identifier);
+ }
+ });
+ }
+ if (callbackRetVal !== false) {
+ details.onSuccess(callbackRetVal);
+ } else {
+ if (details.onFailure) {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Invoking failure callback.");
+ details.onFailure();
+ } else {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Will not proceed.");
+ }
+ }
+ return callbackRetVal;
+ },
+ _handleNewFile: function(file, batchId, newFileWrapperList) {
+ var self = this, uuid = qq.getUniqueId(), size = -1, name = qq.getFilename(file), actualFile = file.blob || file, handler = this._customNewFileHandler ? this._customNewFileHandler : qq.bind(self._handleNewFileGeneric, self);
+ if (!qq.isInput(actualFile) && actualFile.size >= 0) {
+ size = actualFile.size;
+ }
+ handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {
+ uploadData: self._uploadData,
+ paramsStore: self._paramsStore,
+ addFileToHandler: function(id, file) {
+ self._handler.add(id, file);
+ self._netUploadedOrQueued++;
+ self._trackButton(id);
+ }
+ });
+ },
+ _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {
+ var id = this._uploadData.addFile({
+ uuid: uuid,
+ name: name,
+ size: size,
+ batchId: batchId
+ });
+ this._handler.add(id, file);
+ this._trackButton(id);
+ this._netUploadedOrQueued++;
+ fileList.push({
+ id: id,
+ file: file
+ });
+ },
+ _handlePasteSuccess: function(blob, extSuppliedName) {
+ var extension = blob.type.split("/")[1], name = extSuppliedName;
+ if (name == null) {
+ name = this._options.paste.defaultName;
+ }
+ name += "." + extension;
+ this.addFiles({
+ name: name,
+ blob: blob
+ });
+ },
+ _initExtraButton: function(spec) {
+ var button = this._createUploadButton({
+ accept: spec.validation.acceptFiles,
+ allowedExtensions: spec.validation.allowedExtensions,
+ element: spec.element,
+ folders: spec.folders,
+ multiple: spec.multiple,
+ title: spec.fileInputTitle
+ });
+ this._extraButtonSpecs[button.getButtonId()] = spec;
+ },
+ _initFormSupportAndParams: function() {
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore = this._createStore(this._options.request.params, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this._options.request.endpoint = this._formSupport.newEndpoint;
+ }
+ } else {
+ this._paramsStore = this._createStore(this._options.request.params);
+ }
+ },
+ _isDeletePossible: function() {
+ if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {
+ return false;
+ }
+ if (this._options.cors.expected) {
+ if (qq.supportedFeatures.deleteFileCorsXhr) {
+ return true;
+ }
+ if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ },
+ _isAllowedExtension: function(allowed, fileName) {
+ var valid = false;
+ if (!allowed.length) {
+ return true;
+ }
+ qq.each(allowed, function(idx, allowedExt) {
+ if (qq.isString(allowedExt)) {
+ var extRegex = new RegExp("\\." + allowedExt + "$", "i");
+ if (fileName.match(extRegex) != null) {
+ valid = true;
+ return false;
+ }
+ }
+ });
+ return valid;
+ },
+ _itemError: function(code, maybeNameOrNames, item) {
+ var message = this._options.messages[code], allowedExtensions = [], names = [].concat(maybeNameOrNames), name = names[0], buttonId = this._getButtonId(item), validationBase = this._getValidationBase(buttonId), extensionsForMessage, placeholderMatch;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {
+ if (qq.isString(allowedExtension)) {
+ allowedExtensions.push(allowedExtension);
+ }
+ });
+ extensionsForMessage = allowedExtensions.join(", ").toLowerCase();
+ r("{file}", this._options.formatFileName(name));
+ r("{extensions}", extensionsForMessage);
+ r("{sizeLimit}", this._formatSize(validationBase.sizeLimit));
+ r("{minSizeLimit}", this._formatSize(validationBase.minSizeLimit));
+ placeholderMatch = message.match(/(\{\w+\})/g);
+ if (placeholderMatch !== null) {
+ qq.each(placeholderMatch, function(idx, placeholder) {
+ r(placeholder, names[idx]);
+ });
+ }
+ this._options.callbacks.onError(null, name, message, undefined);
+ return message;
+ },
+ _manualRetry: function(id, callback) {
+ if (this._onBeforeManualRetry(id)) {
+ this._netUploadedOrQueued++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ if (callback) {
+ callback(id);
+ } else {
+ this._handler.retry(id);
+ }
+ return true;
+ }
+ },
+ _maybeAllComplete: function(id, status) {
+ var self = this, notFinished = this._getNotFinished();
+ if (status === qq.status.UPLOAD_SUCCESSFUL) {
+ this._succeededSinceLastAllComplete.push(id);
+ } else if (status === qq.status.UPLOAD_FAILED) {
+ this._failedSinceLastAllComplete.push(id);
+ }
+ if (notFinished === 0 && (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {
+ setTimeout(function() {
+ self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);
+ }, 0);
+ }
+ },
+ _maybeHandleIos8SafariWorkaround: function() {
+ var self = this;
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ setTimeout(function() {
+ window.alert(self._options.messages.unsupportedBrowserIos8Safari);
+ }, 0);
+ throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);
+ }
+ },
+ _maybeParseAndSendUploadError: function(id, name, response, xhr) {
+ if (!response.success) {
+ if (xhr && xhr.status !== 200 && !response.error) {
+ this._options.callbacks.onError(id, name, "XHR returned response code " + xhr.status, xhr);
+ } else {
+ var errorReason = response.error ? response.error : this._options.text.defaultResponseError;
+ this._options.callbacks.onError(id, name, errorReason, xhr);
+ }
+ }
+ },
+ _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {
+ var self = this;
+ if (items.length > index) {
+ if (validItem || !this._options.validation.stopOnFirstInvalidFile) {
+ setTimeout(function() {
+ var validationDescriptor = self._getValidationDescriptor(items[index]), buttonId = self._getButtonId(items[index].file), button = self._getButton(buttonId);
+ self._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),
+ onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),
+ onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),
+ identifier: "Item '" + validationDescriptor.name + "', size: " + validationDescriptor.size
+ });
+ }, 0);
+ } else if (!validItem) {
+ for (;index < items.length; index++) {
+ self._fileOrBlobRejected(items[index].id);
+ }
+ }
+ }
+ },
+ _onAllComplete: function(successful, failed) {
+ this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);
+ this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ },
+ _onAutoRetry: function(id, name, responseJSON, xhr, callback) {
+ var self = this;
+ self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];
+ if (self._shouldAutoRetry(id, name, responseJSON)) {
+ var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1e3;
+ self._maybeParseAndSendUploadError.apply(self, arguments);
+ self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);
+ self._onBeforeAutoRetry(id, name);
+ self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ self._retryTimeouts[id] = setTimeout(function() {
+ self.log("Starting retry for " + name + "...");
+ if (callback) {
+ callback(id);
+ } else {
+ self._handler.retry(id);
+ }
+ }, retryWaitPeriod);
+ return true;
+ }
+ },
+ _onBeforeAutoRetry: function(id, name) {
+ this.log("Waiting " + this._options.retry.autoAttemptDelay + " seconds before retrying " + name + "...");
+ },
+ _onBeforeManualRetry: function(id) {
+ var itemLimit = this._currentItemLimit, fileName;
+ if (this._preventRetries[id]) {
+ this.log("Retries are forbidden for id " + id, "warn");
+ return false;
+ } else if (this._handler.isValid(id)) {
+ fileName = this.getName(id);
+ if (this._options.callbacks.onManualRetry(id, fileName) === false) {
+ return false;
+ }
+ if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {
+ this._itemError("retryFailTooManyItems");
+ return false;
+ }
+ this.log("Retrying upload for '" + fileName + "' (id: " + id + ")...");
+ return true;
+ } else {
+ this.log("'" + id + "' is not a valid file ID", "error");
+ return false;
+ }
+ },
+ _onCancel: function(id, name) {
+ this._netUploadedOrQueued--;
+ clearTimeout(this._retryTimeouts[id]);
+ var storedItemIndex = qq.indexOf(this._storedIds, id);
+ if (!this._options.autoUpload && storedItemIndex >= 0) {
+ this._storedIds.splice(storedItemIndex, 1);
+ }
+ this._uploadData.setStatus(id, qq.status.CANCELED);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ if (!result.success) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);
+ if (result[this._options.retry.preventRetryResponseProperty] === true) {
+ this._preventRetries[id] = true;
+ }
+ } else {
+ if (result.thumbnailUrl) {
+ this._thumbnailUrls[id] = result.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);
+ }
+ this._maybeParseAndSendUploadError(id, name, result, xhr);
+ return result.success ? true : false;
+ },
+ _onDelete: function(id) {
+ this._uploadData.setStatus(id, qq.status.DELETING);
+ },
+ _onDeleteComplete: function(id, xhrOrXdr, isError) {
+ var name = this.getName(id);
+ if (isError) {
+ this._uploadData.setStatus(id, qq.status.DELETE_FAILED);
+ this.log("Delete request for '" + name + "' has failed.", "error");
+ if (xhrOrXdr.withCredentials === undefined) {
+ this._options.callbacks.onError(id, name, "Delete request failed", xhrOrXdr);
+ } else {
+ this._options.callbacks.onError(id, name, "Delete request failed with response code " + xhrOrXdr.status, xhrOrXdr);
+ }
+ } else {
+ this._netUploadedOrQueued--;
+ this._netUploaded--;
+ this._handler.expunge(id);
+ this._uploadData.setStatus(id, qq.status.DELETED);
+ this.log("Delete request for '" + name + "' has succeeded.");
+ }
+ },
+ _onInputChange: function(input) {
+ var fileIndex;
+ if (qq.supportedFeatures.ajaxUploading) {
+ for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {
+ this._annotateWithButtonId(input.files[fileIndex], input);
+ }
+ this.addFiles(input.files);
+ } else if (input.value.length > 0) {
+ this.addFiles(input);
+ }
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);
+ },
+ _onSubmit: function(id, name) {},
+ _onSubmitCallbackSuccess: function(id, name) {
+ this._onSubmit.apply(this, arguments);
+ this._uploadData.setStatus(id, qq.status.SUBMITTED);
+ this._onSubmitted.apply(this, arguments);
+ if (this._options.autoUpload) {
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ this._uploadFile(id);
+ } else {
+ this._storeForLater(id);
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ }
+ },
+ _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {
+ var uuid = this.getUuid(id), adjustedOnSuccessCallback;
+ if (onSuccessCallback) {
+ adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);
+ }
+ if (this._isDeletePossible()) {
+ this._handleCheckedCallback({
+ name: "onSubmitDelete",
+ callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),
+ onSuccess: adjustedOnSuccessCallback || qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),
+ identifier: id
+ });
+ return true;
+ } else {
+ this.log("Delete request ignored for ID " + id + ", delete feature is disabled or request not possible " + "due to CORS on a user agent that does not support pre-flighting.", "warn");
+ return false;
+ }
+ },
+ _onSubmitted: function(id) {},
+ _onTotalProgress: function(loaded, total) {
+ this._options.callbacks.onTotalProgress(loaded, total);
+ },
+ _onUploadPrep: function(id) {},
+ _onUpload: function(id, name) {
+ this._uploadData.setStatus(id, qq.status.UPLOADING);
+ },
+ _onUploadChunk: function(id, chunkData) {},
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.PAUSED) {
+ clearTimeout(this._retryTimeouts[id]);
+ }
+ },
+ _onValidateBatchCallbackFailure: function(fileWrappers) {
+ var self = this;
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ self._fileOrBlobRejected(fileWrapper.id);
+ });
+ },
+ _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {
+ var errorMessage, itemLimit = this._currentItemLimit, proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;
+ if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {
+ if (items.length > 0) {
+ this._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),
+ onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),
+ onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),
+ identifier: "Item '" + items[0].file.name + "', size: " + items[0].file.size
+ });
+ } else {
+ this._itemError("noFilesError");
+ }
+ } else {
+ this._onValidateBatchCallbackFailure(items);
+ errorMessage = this._options.messages.tooManyItemsError.replace(/\{netItems\}/g, proposedNetFilesUploadedOrQueued).replace(/\{itemLimit\}/g, itemLimit);
+ this._batchError(errorMessage);
+ }
+ },
+ _onValidateCallbackFailure: function(items, index, params, endpoint) {
+ var nextIndex = index + 1;
+ this._fileOrBlobRejected(items[index].id, items[index].file.name);
+ this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ },
+ _onValidateCallbackSuccess: function(items, index, params, endpoint) {
+ var self = this, nextIndex = index + 1, validationDescriptor = this._getValidationDescriptor(items[index]);
+ this._validateFileOrBlobData(items[index], validationDescriptor).then(function() {
+ self._upload(items[index].id, params, endpoint);
+ self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);
+ }, function() {
+ self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ });
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ if (items.length === 0) {
+ this._itemError("noFilesError");
+ return;
+ }
+ var validationDescriptors = this._getValidationDescriptors(items), buttonId = this._getButtonId(items[0].file), button = this._getButton(buttonId);
+ this._handleCheckedCallback({
+ name: "onValidateBatch",
+ callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),
+ onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),
+ onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),
+ identifier: "batch validation"
+ });
+ },
+ _preventLeaveInProgress: function() {
+ var self = this;
+ this._disposeSupport.attach(window, "beforeunload", function(e) {
+ if (self.getInProgress()) {
+ e = e || window.event;
+ e.returnValue = self._options.messages.onLeave;
+ return self._options.messages.onLeave;
+ }
+ });
+ },
+ _refreshSessionData: function() {
+ var self = this, options = this._options.session;
+ if (qq.Session && this._options.session.endpoint != null) {
+ if (!this._session) {
+ qq.extend(options, {
+ cors: this._options.cors
+ });
+ options.log = qq.bind(this.log, this);
+ options.addFileRecord = qq.bind(this._addCannedFile, this);
+ this._session = new qq.Session(options);
+ }
+ setTimeout(function() {
+ self._session.refresh().then(function(response, xhrOrXdr) {
+ self._sessionRequestComplete();
+ self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);
+ }, function(response, xhrOrXdr) {
+ self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);
+ });
+ }, 0);
+ }
+ },
+ _sessionRequestComplete: function() {},
+ _setSize: function(id, newSize) {
+ this._uploadData.updateSize(id, newSize);
+ this._totalProgress && this._totalProgress.onNewSize(id);
+ },
+ _shouldAutoRetry: function(id, name, responseJSON) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!this._preventRetries[id] && this._options.retry.enableAuto && uploadData.status !== qq.status.PAUSED) {
+ if (this._autoRetries[id] === undefined) {
+ this._autoRetries[id] = 0;
+ }
+ if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {
+ this._autoRetries[id] += 1;
+ return true;
+ }
+ }
+ return false;
+ },
+ _storeForLater: function(id) {
+ this._storedIds.push(id);
+ },
+ _trackButton: function(id) {
+ var buttonId;
+ if (qq.supportedFeatures.ajaxUploading) {
+ buttonId = this._handler.getFile(id).qqButtonId;
+ } else {
+ buttonId = this._getButtonId(this._handler.getInput(id));
+ }
+ if (buttonId) {
+ this._buttonIdsForFileIds[id] = buttonId;
+ }
+ },
+ _updateFormSupportAndParams: function(formElementOrId) {
+ this._options.form.element = formElementOrId;
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this.setEndpoint(this._formSupport.newEndpoint);
+ }
+ }
+ },
+ _upload: function(id, params, endpoint) {
+ var name = this.getName(id);
+ if (params) {
+ this.setParams(params, id);
+ }
+ if (endpoint) {
+ this.setEndpoint(endpoint, id);
+ }
+ this._handleCheckedCallback({
+ name: "onSubmit",
+ callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),
+ onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),
+ onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),
+ identifier: id
+ });
+ },
+ _uploadFile: function(id) {
+ if (!this._handler.upload(id)) {
+ this._uploadData.setStatus(id, qq.status.QUEUED);
+ }
+ },
+ _uploadStoredFiles: function() {
+ var idToUpload, stillSubmitting, self = this;
+ while (this._storedIds.length) {
+ idToUpload = this._storedIds.shift();
+ this._uploadFile(idToUpload);
+ }
+ stillSubmitting = this.getUploads({
+ status: qq.status.SUBMITTING
+ }).length;
+ if (stillSubmitting) {
+ qq.log("Still waiting for " + stillSubmitting + " files to clear submit queue. Will re-parse stored IDs array shortly.");
+ setTimeout(function() {
+ self._uploadStoredFiles();
+ }, 1e3);
+ }
+ },
+ _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {
+ var self = this, file = function() {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return fileWrapper.file.referenceBlob;
+ }
+ return fileWrapper.file;
+ }(), name = validationDescriptor.name, size = validationDescriptor.size, buttonId = this._getButtonId(fileWrapper.file), validationBase = this._getValidationBase(buttonId), validityChecker = new qq.Promise();
+ validityChecker.then(function() {}, function() {
+ self._fileOrBlobRejected(fileWrapper.id, name);
+ });
+ if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {
+ this._itemError("typeError", name, file);
+ return validityChecker.failure();
+ }
+ if (!this._options.validation.allowEmpty && size === 0) {
+ this._itemError("emptyError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {
+ this._itemError("sizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && size < validationBase.minSizeLimit) {
+ this._itemError("minSizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {
+ new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(validityChecker.success, function(errorCode) {
+ self._itemError(errorCode + "ImageError", name, file);
+ validityChecker.failure();
+ });
+ } else {
+ validityChecker.success();
+ }
+ return validityChecker;
+ },
+ _wrapCallbacks: function() {
+ var self, safeCallback, prop;
+ self = this;
+ safeCallback = function(name, callback, args) {
+ var errorMsg;
+ try {
+ return callback.apply(self, args);
+ } catch (exception) {
+ errorMsg = exception.message || exception.toString();
+ self.log("Caught exception in '" + name + "' callback - " + errorMsg, "error");
+ }
+ };
+ for (prop in this._options.callbacks) {
+ (function() {
+ var callbackName, callbackFunc;
+ callbackName = prop;
+ callbackFunc = self._options.callbacks[callbackName];
+ self._options.callbacks[callbackName] = function() {
+ return safeCallback(callbackName, callbackFunc, arguments);
+ };
+ })();
+ }
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.FineUploaderBasic = function(o) {
+ var self = this;
+ this._options = {
+ debug: false,
+ button: null,
+ multiple: true,
+ maxConnections: 3,
+ disableCancelForFormUploads: false,
+ autoUpload: true,
+ request: {
+ customHeaders: {},
+ endpoint: "/server/upload",
+ filenameParam: "qqfilename",
+ forceMultipart: true,
+ inputName: "qqfile",
+ method: "POST",
+ params: {},
+ paramsInBody: true,
+ totalFileSizeName: "qqtotalfilesize",
+ uuidName: "qquuid"
+ },
+ validation: {
+ allowedExtensions: [],
+ sizeLimit: 0,
+ minSizeLimit: 0,
+ itemLimit: 0,
+ stopOnFirstInvalidFile: true,
+ acceptFiles: null,
+ image: {
+ maxHeight: 0,
+ maxWidth: 0,
+ minHeight: 0,
+ minWidth: 0
+ },
+ allowEmpty: false
+ },
+ callbacks: {
+ onSubmit: function(id, name) {},
+ onSubmitted: function(id, name) {},
+ onComplete: function(id, name, responseJSON, maybeXhr) {},
+ onAllComplete: function(successful, failed) {},
+ onCancel: function(id, name) {},
+ onUpload: function(id, name) {},
+ onUploadChunk: function(id, name, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onProgress: function(id, name, loaded, total) {},
+ onTotalProgress: function(loaded, total) {},
+ onError: function(id, name, reason, maybeXhrOrXdr) {},
+ onAutoRetry: function(id, name, attemptNumber) {},
+ onManualRetry: function(id, name) {},
+ onValidateBatch: function(fileOrBlobData) {},
+ onValidate: function(fileOrBlobData) {},
+ onSubmitDelete: function(id) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {},
+ onPasteReceived: function(blob) {},
+ onStatusChange: function(id, oldStatus, newStatus) {},
+ onSessionRequestComplete: function(response, success, xhrOrXdr) {}
+ },
+ messages: {
+ typeError: "{file} has an invalid extension. Valid extension(s): {extensions}.",
+ sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
+ minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
+ emptyError: "{file} is empty, please select files again without it.",
+ noFilesError: "No files to upload.",
+ tooManyItemsError: "Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.",
+ maxHeightImageError: "Image is too tall.",
+ maxWidthImageError: "Image is too wide.",
+ minHeightImageError: "Image is not tall enough.",
+ minWidthImageError: "Image is not wide enough.",
+ retryFailTooManyItems: "Retry failed - you have reached your file limit.",
+ onLeave: "The files are being uploaded, if you leave now the upload will be canceled.",
+ unsupportedBrowserIos8Safari: "Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues."
+ },
+ retry: {
+ enableAuto: false,
+ maxAutoAttempts: 3,
+ autoAttemptDelay: 5,
+ preventRetryResponseProperty: "preventRetry"
+ },
+ classes: {
+ buttonHover: "qq-upload-button-hover",
+ buttonFocus: "qq-upload-button-focus"
+ },
+ chunking: {
+ enabled: false,
+ concurrent: {
+ enabled: false
+ },
+ mandatory: false,
+ paramNames: {
+ partIndex: "qqpartindex",
+ partByteOffset: "qqpartbyteoffset",
+ chunkSize: "qqchunksize",
+ totalFileSize: "qqtotalfilesize",
+ totalParts: "qqtotalparts"
+ },
+ partSize: 2e6,
+ success: {
+ endpoint: null
+ }
+ },
+ resume: {
+ enabled: false,
+ recordsExpireIn: 7,
+ paramNames: {
+ resuming: "qqresume"
+ }
+ },
+ formatFileName: function(fileOrBlobName) {
+ return fileOrBlobName;
+ },
+ text: {
+ defaultResponseError: "Upload failure reason unknown",
+ fileInputTitle: "file input",
+ sizeSymbols: [ "kB", "MB", "GB", "TB", "PB", "EB" ]
+ },
+ deleteFile: {
+ enabled: false,
+ method: "DELETE",
+ endpoint: "/server/upload",
+ customHeaders: {},
+ params: {}
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false,
+ allowXdr: false
+ },
+ blobs: {
+ defaultName: "misc_data"
+ },
+ paste: {
+ targetElement: null,
+ defaultName: "pasted_image"
+ },
+ camera: {
+ ios: false,
+ button: null
+ },
+ extraButtons: [],
+ session: {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ refreshOnReset: true
+ },
+ form: {
+ element: "qq-form",
+ autoUpload: false,
+ interceptSubmit: true
+ },
+ scaling: {
+ customResizer: null,
+ sendOriginal: true,
+ orient: true,
+ defaultType: null,
+ defaultQuality: 80,
+ failureText: "Failed to scale",
+ includeExif: false,
+ sizes: []
+ },
+ workarounds: {
+ iosEmptyVideos: true,
+ ios8SafariUploads: true,
+ ios8BrowserCrash: false
+ }
+ };
+ qq.extend(this._options, o, true);
+ this._buttons = [];
+ this._extraButtonSpecs = {};
+ this._buttonIdsForFileIds = [];
+ this._wrapCallbacks();
+ this._disposeSupport = new qq.DisposeSupport();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData = this._createUploadDataTracker();
+ this._initFormSupportAndParams();
+ this._customHeadersStore = this._createStore(this._options.request.customHeaders);
+ this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);
+ this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);
+ this._endpointStore = this._createStore(this._options.request.endpoint);
+ this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);
+ this._handler = this._createUploadHandler();
+ this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();
+ if (this._options.button) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._options.button,
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._generateExtraButtonSpecs();
+ this._handleCameraAccess();
+ if (this._options.paste.targetElement) {
+ if (qq.PasteSupport) {
+ this._pasteHandler = this._createPasteHandler();
+ } else {
+ this.log("Paste support module not found", "error");
+ }
+ }
+ this._preventLeaveInProgress();
+ this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));
+ this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._scaler = qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this)) || {};
+ if (this._scaler.enabled) {
+ this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);
+ }
+ if (qq.TotalProgress && qq.supportedFeatures.progressBar) {
+ this._totalProgress = new qq.TotalProgress(qq.bind(this._onTotalProgress, this), function(id) {
+ var entry = self._uploadData.retrieve({
+ id: id
+ });
+ return entry && entry.size || 0;
+ });
+ }
+ this._currentItemLimit = this._options.validation.itemLimit;
+ };
+ qq.FineUploaderBasic.prototype = qq.basePublicApi;
+ qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);
+ })();
+ qq.AjaxRequester = function(o) {
+ "use strict";
+ var log, shouldParamsBeInQueryString, queue = [], requestData = {}, options = {
+ acceptHeader: null,
+ validMethods: [ "PATCH", "POST", "PUT" ],
+ method: "POST",
+ contentType: "application/x-www-form-urlencoded",
+ maxConnections: 3,
+ customHeaders: {},
+ endpointStore: {},
+ paramsStore: {},
+ mandatedParams: {},
+ allowXRequestedWithAndCacheControl: true,
+ successfulResponseCodes: {
+ DELETE: [ 200, 202, 204 ],
+ PATCH: [ 200, 201, 202, 203, 204 ],
+ POST: [ 200, 201, 202, 203, 204 ],
+ PUT: [ 200, 201, 202, 203, 204 ],
+ GET: [ 200 ]
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onSend: function(id) {},
+ onComplete: function(id, xhrOrXdr, isError) {},
+ onProgress: null
+ };
+ qq.extend(options, o);
+ log = options.log;
+ if (qq.indexOf(options.validMethods, options.method) < 0) {
+ throw new Error("'" + options.method + "' is not a supported method for this type of request!");
+ }
+ function isSimpleMethod() {
+ return qq.indexOf([ "GET", "POST", "HEAD" ], options.method) >= 0;
+ }
+ function containsNonSimpleHeaders(headers) {
+ var containsNonSimple = false;
+ qq.each(containsNonSimple, function(idx, header) {
+ if (qq.indexOf([ "Accept", "Accept-Language", "Content-Language", "Content-Type" ], header) < 0) {
+ containsNonSimple = true;
+ return false;
+ }
+ });
+ return containsNonSimple;
+ }
+ function isXdr(xhr) {
+ return options.cors.expected && xhr.withCredentials === undefined;
+ }
+ function getCorsAjaxTransport() {
+ var xhrOrXdr;
+ if (window.XMLHttpRequest || window.ActiveXObject) {
+ xhrOrXdr = qq.createXhrInstance();
+ if (xhrOrXdr.withCredentials === undefined) {
+ xhrOrXdr = new XDomainRequest();
+ xhrOrXdr.onload = function() {};
+ xhrOrXdr.onerror = function() {};
+ xhrOrXdr.ontimeout = function() {};
+ xhrOrXdr.onprogress = function() {};
+ }
+ }
+ return xhrOrXdr;
+ }
+ function getXhrOrXdr(id, suppliedXhr) {
+ var xhrOrXdr = requestData[id].xhr;
+ if (!xhrOrXdr) {
+ if (suppliedXhr) {
+ xhrOrXdr = suppliedXhr;
+ } else {
+ if (options.cors.expected) {
+ xhrOrXdr = getCorsAjaxTransport();
+ } else {
+ xhrOrXdr = qq.createXhrInstance();
+ }
+ }
+ requestData[id].xhr = xhrOrXdr;
+ }
+ return xhrOrXdr;
+ }
+ function dequeue(id) {
+ var i = qq.indexOf(queue, id), max = options.maxConnections, nextId;
+ delete requestData[id];
+ queue.splice(i, 1);
+ if (queue.length >= max && i < max) {
+ nextId = queue[max - 1];
+ sendRequest(nextId);
+ }
+ }
+ function onComplete(id, xdrError) {
+ var xhr = getXhrOrXdr(id), method = options.method, isError = xdrError === true;
+ dequeue(id);
+ if (isError) {
+ log(method + " request for " + id + " has failed", "error");
+ } else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {
+ isError = true;
+ log(method + " request for " + id + " has failed - response code " + xhr.status, "error");
+ }
+ options.onComplete(id, xhr, isError);
+ }
+ function getParams(id) {
+ var onDemandParams = requestData[id].additionalParams, mandatedParams = options.mandatedParams, params;
+ if (options.paramsStore.get) {
+ params = options.paramsStore.get(id);
+ }
+ if (onDemandParams) {
+ qq.each(onDemandParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ if (mandatedParams) {
+ qq.each(mandatedParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ return params;
+ }
+ function sendRequest(id, optXhr) {
+ var xhr = getXhrOrXdr(id, optXhr), method = options.method, params = getParams(id), payload = requestData[id].payload, url;
+ options.onSend(id);
+ url = createUrl(id, params, requestData[id].additionalQueryParams);
+ if (isXdr(xhr)) {
+ xhr.onload = getXdrLoadHandler(id);
+ xhr.onerror = getXdrErrorHandler(id);
+ } else {
+ xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);
+ }
+ registerForUploadProgress(id);
+ xhr.open(method, url, true);
+ if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {
+ xhr.withCredentials = true;
+ }
+ setHeaders(id);
+ log("Sending " + method + " request for " + id);
+ if (payload) {
+ xhr.send(payload);
+ } else if (shouldParamsBeInQueryString || !params) {
+ xhr.send();
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/x-www-form-urlencoded") >= 0) {
+ xhr.send(qq.obj2url(params, ""));
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/json") >= 0) {
+ xhr.send(JSON.stringify(params));
+ } else {
+ xhr.send(params);
+ }
+ return xhr;
+ }
+ function createUrl(id, params, additionalQueryParams) {
+ var endpoint = options.endpointStore.get(id), addToPath = requestData[id].addToPath;
+ if (addToPath != undefined) {
+ endpoint += "/" + addToPath;
+ }
+ if (shouldParamsBeInQueryString && params) {
+ endpoint = qq.obj2url(params, endpoint);
+ }
+ if (additionalQueryParams) {
+ endpoint = qq.obj2url(additionalQueryParams, endpoint);
+ }
+ return endpoint;
+ }
+ function getXhrReadyStateChangeHandler(id) {
+ return function() {
+ if (getXhrOrXdr(id).readyState === 4) {
+ onComplete(id);
+ }
+ };
+ }
+ function registerForUploadProgress(id) {
+ var onProgress = options.onProgress;
+ if (onProgress) {
+ getXhrOrXdr(id).upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ onProgress(id, e.loaded, e.total);
+ }
+ };
+ }
+ }
+ function getXdrLoadHandler(id) {
+ return function() {
+ onComplete(id);
+ };
+ }
+ function getXdrErrorHandler(id) {
+ return function() {
+ onComplete(id, true);
+ };
+ }
+ function setHeaders(id) {
+ var xhr = getXhrOrXdr(id), customHeaders = options.customHeaders, onDemandHeaders = requestData[id].additionalHeaders || {}, method = options.method, allHeaders = {};
+ if (!isXdr(xhr)) {
+ options.acceptHeader && xhr.setRequestHeader("Accept", options.acceptHeader);
+ if (options.allowXRequestedWithAndCacheControl) {
+ if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ xhr.setRequestHeader("Cache-Control", "no-cache");
+ }
+ }
+ if (options.contentType && (method === "POST" || method === "PUT")) {
+ xhr.setRequestHeader("Content-Type", options.contentType);
+ }
+ qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);
+ qq.extend(allHeaders, onDemandHeaders);
+ qq.each(allHeaders, function(name, val) {
+ xhr.setRequestHeader(name, val);
+ });
+ }
+ }
+ function isResponseSuccessful(responseCode) {
+ return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;
+ }
+ function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {
+ requestData[id] = {
+ addToPath: addToPath,
+ additionalParams: additionalParams,
+ additionalQueryParams: additionalQueryParams,
+ additionalHeaders: additionalHeaders,
+ payload: payload
+ };
+ var len = queue.push(id);
+ if (len <= options.maxConnections) {
+ return sendRequest(id, optXhr);
+ }
+ }
+ shouldParamsBeInQueryString = options.method === "GET" || options.method === "DELETE";
+ qq.extend(this, {
+ initTransport: function(id) {
+ var path, params, headers, payload, cacheBuster, additionalQueryParams;
+ return {
+ withPath: function(appendToPath) {
+ path = appendToPath;
+ return this;
+ },
+ withParams: function(additionalParams) {
+ params = additionalParams;
+ return this;
+ },
+ withQueryParams: function(_additionalQueryParams_) {
+ additionalQueryParams = _additionalQueryParams_;
+ return this;
+ },
+ withHeaders: function(additionalHeaders) {
+ headers = additionalHeaders;
+ return this;
+ },
+ withPayload: function(thePayload) {
+ payload = thePayload;
+ return this;
+ },
+ withCacheBuster: function() {
+ cacheBuster = true;
+ return this;
+ },
+ send: function(optXhr) {
+ if (cacheBuster && qq.indexOf([ "GET", "DELETE" ], options.method) >= 0) {
+ params.qqtimestamp = new Date().getTime();
+ }
+ return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);
+ }
+ };
+ },
+ canceled: function(id) {
+ dequeue(id);
+ }
+ });
+ };
+ qq.UploadHandler = function(spec) {
+ "use strict";
+ var proxy = spec.proxy, fileState = {}, onCancel = proxy.onCancel, getName = proxy.getName;
+ qq.extend(this, {
+ add: function(id, fileItem) {
+ fileState[id] = fileItem;
+ fileState[id].temp = {};
+ },
+ cancel: function(id) {
+ var self = this, cancelFinalizationEffort = new qq.Promise(), onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);
+ onCancelRetVal.then(function() {
+ if (self.isValid(id)) {
+ fileState[id].canceled = true;
+ self.expunge(id);
+ }
+ cancelFinalizationEffort.success();
+ });
+ },
+ expunge: function(id) {
+ delete fileState[id];
+ },
+ getThirdPartyFileId: function(id) {
+ return fileState[id].key;
+ },
+ isValid: function(id) {
+ return fileState[id] !== undefined;
+ },
+ reset: function() {
+ fileState = {};
+ },
+ _getFileState: function(id) {
+ return fileState[id];
+ },
+ _setThirdPartyFileId: function(id, thirdPartyFileId) {
+ fileState[id].key = thirdPartyFileId;
+ },
+ _wasCanceled: function(id) {
+ return !!fileState[id].canceled;
+ }
+ });
+ };
+ qq.UploadHandlerController = function(o, namespace) {
+ "use strict";
+ var controller = this, chunkingPossible = false, concurrentChunkingPossible = false, chunking, preventRetryResponse, log, handler, options = {
+ paramsStore: {},
+ maxConnections: 3,
+ chunking: {
+ enabled: false,
+ multiple: {
+ enabled: false
+ }
+ },
+ log: function(str, level) {},
+ onProgress: function(id, fileName, loaded, total) {},
+ onComplete: function(id, fileName, response, xhr) {},
+ onCancel: function(id, fileName) {},
+ onUploadPrep: function(id) {},
+ onUpload: function(id, fileName) {},
+ onUploadChunk: function(id, fileName, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, response, xhr) {},
+ onAutoRetry: function(id, fileName, response, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onUuidChanged: function(id, newUuid) {},
+ getName: function(id) {},
+ setSize: function(id, newSize) {},
+ isQueued: function(id) {},
+ getIdsInProxyGroup: function(id) {},
+ getIdsInBatch: function(id) {}
+ }, chunked = {
+ done: function(id, chunkIdx, response, xhr) {
+ var chunkData = handler._getChunkData(id, chunkIdx);
+ handler._getFileState(id).attemptingResume = false;
+ delete handler._getFileState(id).temp.chunkProgress[chunkIdx];
+ handler._getFileState(id).loaded += chunkData.size;
+ options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);
+ },
+ finalize: function(id) {
+ var size = options.getSize(id), name = options.getName(id);
+ log("All chunks have been uploaded for " + id + " - finalizing....");
+ handler.finalizeChunks(id).then(function(response, xhr) {
+ log("Finalize successful for " + id);
+ var normaizedResponse = upload.normalizeResponse(response, true);
+ options.onProgress(id, name, size, size);
+ handler._maybeDeletePersistedChunkData(id);
+ upload.cleanup(id, normaizedResponse, xhr);
+ }, function(response, xhr) {
+ var normaizedResponse = upload.normalizeResponse(response, false);
+ log("Problem finalizing chunks for file ID " + id + " - " + normaizedResponse.error, "error");
+ if (normaizedResponse.reset) {
+ chunked.reset(id);
+ }
+ if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {
+ upload.cleanup(id, normaizedResponse, xhr);
+ }
+ });
+ },
+ handleFailure: function(chunkIdx, id, response, xhr) {
+ var name = options.getName(id);
+ log("Chunked upload request failed for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var responseToReport = upload.normalizeResponse(response, false), inProgressIdx;
+ if (responseToReport.reset) {
+ chunked.reset(id);
+ } else {
+ inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);
+ if (inProgressIdx >= 0) {
+ handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);
+ handler._getFileState(id).chunking.remaining.unshift(chunkIdx);
+ }
+ }
+ if (!handler._getFileState(id).temp.ignoreFailure) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = true;
+ log(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));
+ qq.each(handler._getXhrs(id), function(ckid, ckXhr) {
+ log(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ", id, ckid, ckXhr.readyState));
+ ckXhr.abort();
+ ckXhr._cancelled = true;
+ });
+ handler.moveInProgressToRemaining(id);
+ connectionManager.free(id, true);
+ }
+ if (!options.onAutoRetry(id, name, responseToReport, xhr)) {
+ upload.cleanup(id, responseToReport, xhr);
+ }
+ }
+ },
+ hasMoreParts: function(id) {
+ return !!handler._getFileState(id).chunking.remaining.length;
+ },
+ nextPart: function(id) {
+ var nextIdx = handler._getFileState(id).chunking.remaining.shift();
+ if (nextIdx >= handler._getTotalChunks(id)) {
+ nextIdx = null;
+ }
+ return nextIdx;
+ },
+ reset: function(id) {
+ log("Server or callback has ordered chunking effort to be restarted on next attempt for item ID " + id, "error");
+ handler._maybeDeletePersistedChunkData(id);
+ handler.reevaluateChunking(id);
+ handler._getFileState(id).loaded = 0;
+ },
+ sendNext: function(id) {
+ var size = options.getSize(id), name = options.getName(id), chunkIdx = chunked.nextPart(id), chunkData = handler._getChunkData(id, chunkIdx), resuming = handler._getFileState(id).attemptingResume, inProgressChunks = handler._getFileState(id).chunking.inProgress || [];
+ if (handler._getFileState(id).loaded == null) {
+ handler._getFileState(id).loaded = 0;
+ }
+ if (resuming && options.onResume(id, name, chunkData) === false) {
+ chunked.reset(id);
+ chunkIdx = chunked.nextPart(id);
+ chunkData = handler._getChunkData(id, chunkIdx);
+ resuming = false;
+ }
+ if (chunkIdx == null && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else {
+ log(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.", id, chunkIdx, chunkData.start + 1, chunkData.end, size));
+ options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));
+ inProgressChunks.push(chunkIdx);
+ handler._getFileState(id).chunking.inProgress = inProgressChunks;
+ if (concurrentChunkingPossible) {
+ connectionManager.open(id, chunkIdx);
+ }
+ if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {
+ chunked.sendNext(id);
+ }
+ if (chunkData.blob.size === 0) {
+ log(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.", chunkIdx, id), "error");
+ chunked.handleFailure(chunkIdx, id, "File is no longer available", null);
+ } else {
+ handler.uploadChunk(id, chunkIdx, resuming).then(function success(response, xhr) {
+ log("Chunked upload request succeeded for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var inProgressChunks = handler._getFileState(id).chunking.inProgress || [], responseToReport = upload.normalizeResponse(response, true), inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);
+ log(qq.format("Chunk {} for file {} uploaded successfully.", chunkIdx, id));
+ chunked.done(id, chunkIdx, responseToReport, xhr);
+ if (inProgressChunkIdx >= 0) {
+ inProgressChunks.splice(inProgressChunkIdx, 1);
+ }
+ handler._maybePersistChunkedState(id);
+ if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else if (chunked.hasMoreParts(id)) {
+ chunked.sendNext(id);
+ } else {
+ log(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}", id, JSON.stringify(inProgressChunks)));
+ }
+ }, function failure(response, xhr) {
+ chunked.handleFailure(chunkIdx, id, response, xhr);
+ }).done(function() {
+ handler.clearXhr(id, chunkIdx);
+ });
+ }
+ }
+ }
+ }, connectionManager = {
+ _open: [],
+ _openChunks: {},
+ _waiting: [],
+ available: function() {
+ var max = options.maxConnections, openChunkEntriesCount = 0, openChunksCount = 0;
+ qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {
+ openChunkEntriesCount++;
+ openChunksCount += openChunkIndexes.length;
+ });
+ return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);
+ },
+ free: function(id, dontAllowNext) {
+ var allowNext = !dontAllowNext, waitingIndex = qq.indexOf(connectionManager._waiting, id), connectionsIndex = qq.indexOf(connectionManager._open, id), nextId;
+ delete connectionManager._openChunks[id];
+ if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {
+ log("Generated blob upload has ended for " + id + ", disposing generated blob.");
+ delete handler._getFileState(id).file;
+ }
+ if (waitingIndex >= 0) {
+ connectionManager._waiting.splice(waitingIndex, 1);
+ } else if (allowNext && connectionsIndex >= 0) {
+ connectionManager._open.splice(connectionsIndex, 1);
+ nextId = connectionManager._waiting.shift();
+ if (nextId >= 0) {
+ connectionManager._open.push(nextId);
+ upload.start(nextId);
+ }
+ }
+ },
+ getWaitingOrConnected: function() {
+ var waitingOrConnected = [];
+ qq.each(connectionManager._openChunks, function(fileId, chunks) {
+ if (chunks && chunks.length) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ qq.each(connectionManager._open, function(idx, fileId) {
+ if (!connectionManager._openChunks[fileId]) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);
+ return waitingOrConnected;
+ },
+ isUsingConnection: function(id) {
+ return qq.indexOf(connectionManager._open, id) >= 0;
+ },
+ open: function(id, chunkIdx) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.push(id);
+ }
+ if (connectionManager.available()) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.pop();
+ connectionManager._open.push(id);
+ } else {
+ (function() {
+ var openChunksEntry = connectionManager._openChunks[id] || [];
+ openChunksEntry.push(chunkIdx);
+ connectionManager._openChunks[id] = openChunksEntry;
+ })();
+ }
+ return true;
+ }
+ return false;
+ },
+ reset: function() {
+ connectionManager._waiting = [];
+ connectionManager._open = [];
+ }
+ }, simple = {
+ send: function(id, name) {
+ handler._getFileState(id).loaded = 0;
+ log("Sending simple upload request for " + id);
+ handler.uploadFile(id).then(function(response, optXhr) {
+ log("Simple upload request succeeded for " + id);
+ var responseToReport = upload.normalizeResponse(response, true), size = options.getSize(id);
+ options.onProgress(id, name, size, size);
+ upload.maybeNewUuid(id, responseToReport);
+ upload.cleanup(id, responseToReport, optXhr);
+ }, function(response, optXhr) {
+ log("Simple upload request failed for " + id);
+ var responseToReport = upload.normalizeResponse(response, false);
+ if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {
+ upload.cleanup(id, responseToReport, optXhr);
+ }
+ });
+ }
+ }, upload = {
+ cancel: function(id) {
+ log("Cancelling " + id);
+ options.paramsStore.remove(id);
+ connectionManager.free(id);
+ },
+ cleanup: function(id, response, optXhr) {
+ var name = options.getName(id);
+ options.onComplete(id, name, response, optXhr);
+ if (handler._getFileState(id)) {
+ handler._clearXhrs && handler._clearXhrs(id);
+ }
+ connectionManager.free(id);
+ },
+ getProxyOrBlob: function(id) {
+ return handler.getProxy && handler.getProxy(id) || handler.getFile && handler.getFile(id);
+ },
+ initHandler: function() {
+ var handlerType = namespace ? qq[namespace] : qq.traditional, handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? "Xhr" : "Form";
+ handler = new handlerType[handlerModuleSubtype + "UploadHandler"](options, {
+ getDataByUuid: options.getDataByUuid,
+ getName: options.getName,
+ getSize: options.getSize,
+ getUuid: options.getUuid,
+ log: log,
+ onCancel: options.onCancel,
+ onProgress: options.onProgress,
+ onUuidChanged: options.onUuidChanged
+ });
+ if (handler._removeExpiredChunkingRecords) {
+ handler._removeExpiredChunkingRecords();
+ }
+ },
+ isDeferredEligibleForUpload: function(id) {
+ return options.isQueued(id);
+ },
+ maybeDefer: function(id, blob) {
+ if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {
+ options.onUploadPrep(id);
+ log("Attempting to generate a blob on-demand for " + id);
+ blob.create().then(function(generatedBlob) {
+ log("Generated an on-demand blob for " + id);
+ handler.updateBlob(id, generatedBlob);
+ options.setSize(id, generatedBlob.size);
+ handler.reevaluateChunking(id);
+ upload.maybeSendDeferredFiles(id);
+ }, function(errorMessage) {
+ var errorResponse = {};
+ if (errorMessage) {
+ errorResponse.error = errorMessage;
+ }
+ log(qq.format("Failed to generate blob for ID {}. Error message: {}.", id, errorMessage), "error");
+ options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);
+ upload.maybeSendDeferredFiles(id);
+ connectionManager.free(id);
+ });
+ } else {
+ return upload.maybeSendDeferredFiles(id);
+ }
+ return false;
+ },
+ maybeSendDeferredFiles: function(id) {
+ var idsInGroup = options.getIdsInProxyGroup(id), uploadedThisId = false;
+ if (idsInGroup && idsInGroup.length) {
+ log("Maybe ready to upload proxy group file " + id);
+ qq.each(idsInGroup, function(idx, idInGroup) {
+ if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {
+ uploadedThisId = idInGroup === id;
+ upload.now(idInGroup);
+ } else if (upload.isDeferredEligibleForUpload(idInGroup)) {
+ return false;
+ }
+ });
+ } else {
+ uploadedThisId = true;
+ upload.now(id);
+ }
+ return uploadedThisId;
+ },
+ maybeNewUuid: function(id, response) {
+ if (response.newUuid !== undefined) {
+ options.onUuidChanged(id, response.newUuid);
+ }
+ },
+ normalizeResponse: function(originalResponse, successful) {
+ var response = originalResponse;
+ if (!qq.isObject(originalResponse)) {
+ response = {};
+ if (qq.isString(originalResponse) && !successful) {
+ response.error = originalResponse;
+ }
+ }
+ response.success = successful;
+ return response;
+ },
+ now: function(id) {
+ var name = options.getName(id);
+ if (!controller.isValid(id)) {
+ throw new qq.Error(id + " is not a valid file ID to upload!");
+ }
+ options.onUpload(id, name);
+ if (chunkingPossible && handler._shouldChunkThisFile(id)) {
+ chunked.sendNext(id);
+ } else {
+ simple.send(id, name);
+ }
+ },
+ start: function(id) {
+ var blobToUpload = upload.getProxyOrBlob(id);
+ if (blobToUpload) {
+ return upload.maybeDefer(id, blobToUpload);
+ } else {
+ upload.now(id);
+ return true;
+ }
+ }
+ };
+ qq.extend(this, {
+ add: function(id, file) {
+ handler.add.apply(this, arguments);
+ },
+ upload: function(id) {
+ if (connectionManager.open(id)) {
+ return upload.start(id);
+ }
+ return false;
+ },
+ retry: function(id) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = false;
+ }
+ if (connectionManager.isUsingConnection(id)) {
+ return upload.start(id);
+ } else {
+ return controller.upload(id);
+ }
+ },
+ cancel: function(id) {
+ var cancelRetVal = handler.cancel(id);
+ if (qq.isGenericPromise(cancelRetVal)) {
+ cancelRetVal.then(function() {
+ upload.cancel(id);
+ });
+ } else if (cancelRetVal !== false) {
+ upload.cancel(id);
+ }
+ },
+ cancelAll: function() {
+ var waitingOrConnected = connectionManager.getWaitingOrConnected(), i;
+ if (waitingOrConnected.length) {
+ for (i = waitingOrConnected.length - 1; i >= 0; i--) {
+ controller.cancel(waitingOrConnected[i]);
+ }
+ }
+ connectionManager.reset();
+ },
+ getFile: function(id) {
+ if (handler.getProxy && handler.getProxy(id)) {
+ return handler.getProxy(id).referenceBlob;
+ }
+ return handler.getFile && handler.getFile(id);
+ },
+ isProxied: function(id) {
+ return !!(handler.getProxy && handler.getProxy(id));
+ },
+ getInput: function(id) {
+ if (handler.getInput) {
+ return handler.getInput(id);
+ }
+ },
+ reset: function() {
+ log("Resetting upload handler");
+ controller.cancelAll();
+ connectionManager.reset();
+ handler.reset();
+ },
+ expunge: function(id) {
+ if (controller.isValid(id)) {
+ return handler.expunge(id);
+ }
+ },
+ isValid: function(id) {
+ return handler.isValid(id);
+ },
+ getResumableFilesData: function() {
+ if (handler.getResumableFilesData) {
+ return handler.getResumableFilesData();
+ }
+ return [];
+ },
+ getThirdPartyFileId: function(id) {
+ if (controller.isValid(id)) {
+ return handler.getThirdPartyFileId(id);
+ }
+ },
+ pause: function(id) {
+ if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {
+ connectionManager.free(id);
+ handler.moveInProgressToRemaining(id);
+ return true;
+ }
+ return false;
+ },
+ isResumable: function(id) {
+ return !!handler.isResumable && handler.isResumable(id);
+ }
+ });
+ qq.extend(options, o);
+ log = options.log;
+ chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;
+ concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;
+ preventRetryResponse = function() {
+ var response = {};
+ response[options.preventRetryParam] = true;
+ return response;
+ }();
+ upload.initHandler();
+ };
+ qq.WindowReceiveMessage = function(o) {
+ "use strict";
+ var options = {
+ log: function(message, level) {}
+ }, callbackWrapperDetachers = {};
+ qq.extend(options, o);
+ qq.extend(this, {
+ receiveMessage: function(id, callback) {
+ var onMessageCallbackWrapper = function(event) {
+ callback(event.data);
+ };
+ if (window.postMessage) {
+ callbackWrapperDetachers[id] = qq(window).attach("message", onMessageCallbackWrapper);
+ } else {
+ log("iframe message passing not supported in this browser!", "error");
+ }
+ },
+ stopReceivingMessages: function(id) {
+ if (window.postMessage) {
+ var detacher = callbackWrapperDetachers[id];
+ if (detacher) {
+ detacher();
+ }
+ }
+ }
+ });
+ };
+ qq.FormUploadHandler = function(spec) {
+ "use strict";
+ var options = spec.options, handler = this, proxy = spec.proxy, formHandlerInstanceId = qq.getUniqueId(), onloadCallbacks = {}, detachLoadEvents = {}, postMessageCallbackTimers = {}, isCors = options.isCors, inputName = options.inputName, getUuid = proxy.getUuid, log = proxy.log, corsMessageReceiver = new qq.WindowReceiveMessage({
+ log: log
+ });
+ function expungeFile(id) {
+ delete detachLoadEvents[id];
+ if (isCors) {
+ clearTimeout(postMessageCallbackTimers[id]);
+ delete postMessageCallbackTimers[id];
+ corsMessageReceiver.stopReceivingMessages(id);
+ }
+ var iframe = document.getElementById(handler._getIframeName(id));
+ if (iframe) {
+ iframe.setAttribute("src", "javascript:false;");
+ qq(iframe).remove();
+ }
+ }
+ function getFileIdForIframeName(iframeName) {
+ return iframeName.split("_")[0];
+ }
+ function initIframeForUpload(name) {
+ var iframe = qq.toElement("");
+ iframe.setAttribute("id", name);
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+ return iframe;
+ }
+ function registerPostMessageCallback(iframe, callback) {
+ var iframeName = iframe.id, fileId = getFileIdForIframeName(iframeName), uuid = getUuid(fileId);
+ onloadCallbacks[uuid] = callback;
+ detachLoadEvents[fileId] = qq(iframe).attach("load", function() {
+ if (handler.getInput(fileId)) {
+ log("Received iframe load event for CORS upload request (iframe name " + iframeName + ")");
+ postMessageCallbackTimers[iframeName] = setTimeout(function() {
+ var errorMessage = "No valid message received from loaded iframe for iframe name " + iframeName;
+ log(errorMessage, "error");
+ callback({
+ error: errorMessage
+ });
+ }, 1e3);
+ }
+ });
+ corsMessageReceiver.receiveMessage(iframeName, function(message) {
+ log("Received the following window message: '" + message + "'");
+ var fileId = getFileIdForIframeName(iframeName), response = handler._parseJsonResponse(message), uuid = response.uuid, onloadCallback;
+ if (uuid && onloadCallbacks[uuid]) {
+ log("Handling response for iframe name " + iframeName);
+ clearTimeout(postMessageCallbackTimers[iframeName]);
+ delete postMessageCallbackTimers[iframeName];
+ handler._detachLoadEvent(iframeName);
+ onloadCallback = onloadCallbacks[uuid];
+ delete onloadCallbacks[uuid];
+ corsMessageReceiver.stopReceivingMessages(iframeName);
+ onloadCallback(response);
+ } else if (!uuid) {
+ log("'" + message + "' does not contain a UUID - ignoring.");
+ }
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, fileInput) {
+ super_.add(id, {
+ input: fileInput
+ });
+ fileInput.setAttribute("name", inputName);
+ if (fileInput.parentNode) {
+ qq(fileInput).remove();
+ }
+ },
+ expunge: function(id) {
+ expungeFile(id);
+ super_.expunge(id);
+ },
+ isValid: function(id) {
+ return super_.isValid(id) && handler._getFileState(id).input !== undefined;
+ }
+ };
+ });
+ qq.extend(this, {
+ getInput: function(id) {
+ return handler._getFileState(id).input;
+ },
+ _attachLoadEvent: function(iframe, callback) {
+ var responseDescriptor;
+ if (isCors) {
+ registerPostMessageCallback(iframe, callback);
+ } else {
+ detachLoadEvents[iframe.id] = qq(iframe).attach("load", function() {
+ log("Received response for " + iframe.id);
+ if (!iframe.parentNode) {
+ return;
+ }
+ try {
+ if (iframe.contentDocument && iframe.contentDocument.body && iframe.contentDocument.body.innerHTML == "false") {
+ return;
+ }
+ } catch (error) {
+ log("Error when attempting to access iframe during handling of upload response (" + error.message + ")", "error");
+ responseDescriptor = {
+ success: false
+ };
+ }
+ callback(responseDescriptor);
+ });
+ }
+ },
+ _createIframe: function(id) {
+ var iframeName = handler._getIframeName(id);
+ return initIframeForUpload(iframeName);
+ },
+ _detachLoadEvent: function(id) {
+ if (detachLoadEvents[id] !== undefined) {
+ detachLoadEvents[id]();
+ delete detachLoadEvents[id];
+ }
+ },
+ _getIframeName: function(fileId) {
+ return fileId + "_" + formHandlerInstanceId;
+ },
+ _initFormForUpload: function(spec) {
+ var method = spec.method, endpoint = spec.endpoint, params = spec.params, paramsInBody = spec.paramsInBody, targetName = spec.targetName, form = qq.toElement(" "), url = endpoint;
+ if (paramsInBody) {
+ qq.obj2Inputs(params, form);
+ } else {
+ url = qq.obj2url(params, endpoint);
+ }
+ form.setAttribute("action", url);
+ form.setAttribute("target", targetName);
+ form.style.display = "none";
+ document.body.appendChild(form);
+ return form;
+ },
+ _parseJsonResponse: function(innerHtmlOrMessage) {
+ var response = {};
+ try {
+ response = qq.parseJson(innerHtmlOrMessage);
+ } catch (error) {
+ log("Error when attempting to parse iframe upload response (" + error.message + ")", "error");
+ }
+ return response;
+ }
+ });
+ };
+ qq.XhrUploadHandler = function(spec) {
+ "use strict";
+ var handler = this, namespace = spec.options.namespace, proxy = spec.proxy, chunking = spec.options.chunking, resume = spec.options.resume, chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking, resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume, getName = proxy.getName, getSize = proxy.getSize, getUuid = proxy.getUuid, getEndpoint = proxy.getEndpoint, getDataByUuid = proxy.getDataByUuid, onUuidChanged = proxy.onUuidChanged, onProgress = proxy.onProgress, log = proxy.log;
+ function abort(id) {
+ qq.each(handler._getXhrs(id), function(xhrId, xhr) {
+ var ajaxRequester = handler._getAjaxRequester(id, xhrId);
+ xhr.onreadystatechange = null;
+ xhr.upload.onprogress = null;
+ xhr.abort();
+ ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, blobOrProxy) {
+ if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {
+ super_.add(id, {
+ file: blobOrProxy
+ });
+ } else if (blobOrProxy instanceof qq.BlobProxy) {
+ super_.add(id, {
+ proxy: blobOrProxy
+ });
+ } else {
+ throw new Error("Passed obj is not a File, Blob, or proxy");
+ }
+ handler._initTempState(id);
+ resumeEnabled && handler._maybePrepareForResume(id);
+ },
+ expunge: function(id) {
+ abort(id);
+ handler._maybeDeletePersistedChunkData(id);
+ handler._clearXhrs(id);
+ super_.expunge(id);
+ }
+ };
+ });
+ qq.extend(this, {
+ clearCachedChunk: function(id, chunkIdx) {
+ delete handler._getFileState(id).temp.cachedChunks[chunkIdx];
+ },
+ clearXhr: function(id, chunkIdx) {
+ var tempState = handler._getFileState(id).temp;
+ if (tempState.xhrs) {
+ delete tempState.xhrs[chunkIdx];
+ }
+ if (tempState.ajaxRequesters) {
+ delete tempState.ajaxRequesters[chunkIdx];
+ }
+ },
+ finalizeChunks: function(id, responseParser) {
+ var lastChunkIdx = handler._getTotalChunks(id) - 1, xhr = handler._getXhr(id, lastChunkIdx);
+ if (responseParser) {
+ return new qq.Promise().success(responseParser(xhr), xhr);
+ }
+ return new qq.Promise().success({}, xhr);
+ },
+ getFile: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).file;
+ },
+ getProxy: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).proxy;
+ },
+ getResumableFilesData: function() {
+ var resumableFilesData = [];
+ handler._iterateResumeRecords(function(key, uploadData) {
+ handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);
+ var data = {
+ name: uploadData.name,
+ remaining: uploadData.chunking.remaining,
+ size: uploadData.size,
+ uuid: uploadData.uuid
+ };
+ if (uploadData.key) {
+ data.key = uploadData.key;
+ }
+ resumableFilesData.push(data);
+ });
+ return resumableFilesData;
+ },
+ isResumable: function(id) {
+ return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;
+ },
+ moveInProgressToRemaining: function(id, optInProgress, optRemaining) {
+ var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress, remaining = optRemaining || handler._getFileState(id).chunking.remaining;
+ if (inProgress) {
+ log(qq.format("Moving these chunks from in-progress {}, to remaining.", JSON.stringify(inProgress)));
+ inProgress.reverse();
+ qq.each(inProgress, function(idx, chunkIdx) {
+ remaining.unshift(chunkIdx);
+ });
+ inProgress.length = 0;
+ }
+ },
+ pause: function(id) {
+ if (handler.isValid(id)) {
+ log(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.", id, getName(id)));
+ handler._getFileState(id).paused = true;
+ abort(id);
+ return true;
+ }
+ },
+ reevaluateChunking: function(id) {
+ if (chunking && handler.isValid(id)) {
+ var state = handler._getFileState(id), totalChunks, i;
+ delete state.chunking;
+ state.chunking = {};
+ totalChunks = handler._getTotalChunks(id);
+ if (totalChunks > 1 || chunking.mandatory) {
+ state.chunking.enabled = true;
+ state.chunking.parts = totalChunks;
+ state.chunking.remaining = [];
+ for (i = 0; i < totalChunks; i++) {
+ state.chunking.remaining.push(i);
+ }
+ handler._initTempState(id);
+ } else {
+ state.chunking.enabled = false;
+ }
+ }
+ },
+ updateBlob: function(id, newBlob) {
+ if (handler.isValid(id)) {
+ handler._getFileState(id).file = newBlob;
+ }
+ },
+ _clearXhrs: function(id) {
+ var tempState = handler._getFileState(id).temp;
+ qq.each(tempState.ajaxRequesters, function(chunkId) {
+ delete tempState.ajaxRequesters[chunkId];
+ });
+ qq.each(tempState.xhrs, function(chunkId) {
+ delete tempState.xhrs[chunkId];
+ });
+ },
+ _createXhr: function(id, optChunkIdx) {
+ return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());
+ },
+ _getAjaxRequester: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];
+ },
+ _getChunkData: function(id, chunkIndex) {
+ var chunkSize = chunking.partSize, fileSize = getSize(id), fileOrBlob = handler.getFile(id), startBytes = chunkSize * chunkIndex, endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize, totalChunks = handler._getTotalChunks(id), cachedChunks = this._getFileState(id).temp.cachedChunks, blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);
+ cachedChunks[chunkIndex] = blob;
+ return {
+ part: chunkIndex,
+ start: startBytes,
+ end: endBytes,
+ count: totalChunks,
+ blob: blob,
+ size: endBytes - startBytes
+ };
+ },
+ _getChunkDataForCallback: function(chunkData) {
+ return {
+ partIndex: chunkData.part,
+ startByte: chunkData.start + 1,
+ endByte: chunkData.end,
+ totalParts: chunkData.count
+ };
+ },
+ _getLocalStorageId: function(id) {
+ var formatVersion = "5.0", name = getName(id), size = getSize(id), chunkSize = chunking.partSize, endpoint = getEndpoint(id);
+ return qq.format("qq{}resume{}-{}-{}-{}-{}", namespace, formatVersion, name, size, chunkSize, endpoint);
+ },
+ _getMimeType: function(id) {
+ return handler.getFile(id).type;
+ },
+ _getPersistableData: function(id) {
+ return handler._getFileState(id).chunking;
+ },
+ _getTotalChunks: function(id) {
+ if (chunking) {
+ var fileSize = getSize(id), chunkSize = chunking.partSize;
+ return Math.ceil(fileSize / chunkSize);
+ }
+ },
+ _getXhr: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.xhrs[chunkIdx];
+ },
+ _getXhrs: function(id) {
+ return handler._getFileState(id).temp.xhrs;
+ },
+ _iterateResumeRecords: function(callback) {
+ if (resumeEnabled) {
+ qq.each(localStorage, function(key, item) {
+ if (key.indexOf(qq.format("qq{}resume", namespace)) === 0) {
+ var uploadData = JSON.parse(item);
+ callback(key, uploadData);
+ }
+ });
+ }
+ },
+ _initTempState: function(id) {
+ handler._getFileState(id).temp = {
+ ajaxRequesters: {},
+ chunkProgress: {},
+ xhrs: {},
+ cachedChunks: {}
+ };
+ },
+ _markNotResumable: function(id) {
+ handler._getFileState(id).notResumable = true;
+ },
+ _maybeDeletePersistedChunkData: function(id) {
+ var localStorageId;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ if (localStorageId && localStorage.getItem(localStorageId)) {
+ localStorage.removeItem(localStorageId);
+ return true;
+ }
+ }
+ return false;
+ },
+ _maybePrepareForResume: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && state.key === undefined) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = localStorage.getItem(localStorageId);
+ if (persistedData) {
+ persistedData = JSON.parse(persistedData);
+ if (getDataByUuid(persistedData.uuid)) {
+ handler._markNotResumable(id);
+ } else {
+ log(qq.format("Identified file with ID {} and name of {} as resumable.", id, getName(id)));
+ onUuidChanged(id, persistedData.uuid);
+ state.key = persistedData.key;
+ state.chunking = persistedData.chunking;
+ state.loaded = persistedData.loaded;
+ state.attemptingResume = true;
+ handler.moveInProgressToRemaining(id);
+ }
+ }
+ }
+ },
+ _maybePersistChunkedState: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = {
+ name: getName(id),
+ size: getSize(id),
+ uuid: getUuid(id),
+ key: state.key,
+ chunking: state.chunking,
+ loaded: state.loaded,
+ lastUpdated: Date.now()
+ };
+ try {
+ localStorage.setItem(localStorageId, JSON.stringify(persistedData));
+ } catch (error) {
+ log(qq.format("Unable to save resume data for '{}' due to error: '{}'.", id, error.toString()), "warn");
+ }
+ }
+ },
+ _registerProgressHandler: function(id, chunkIdx, chunkSize) {
+ var xhr = handler._getXhr(id, chunkIdx), name = getName(id), progressCalculator = {
+ simple: function(loaded, total) {
+ var fileSize = getSize(id);
+ if (loaded === total) {
+ onProgress(id, name, fileSize, fileSize);
+ } else {
+ onProgress(id, name, loaded >= fileSize ? fileSize - 1 : loaded, fileSize);
+ }
+ },
+ chunked: function(loaded, total) {
+ var chunkProgress = handler._getFileState(id).temp.chunkProgress, totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded, loadedForRequest = loaded, totalForRequest = total, totalFileSize = getSize(id), estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize), totalLoadedForFile = totalSuccessfullyLoadedForFile;
+ chunkProgress[chunkIdx] = estActualChunkLoaded;
+ qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {
+ totalLoadedForFile += chunkLoaded;
+ });
+ onProgress(id, name, totalLoadedForFile, totalFileSize);
+ }
+ };
+ xhr.upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ var type = chunkSize == null ? "simple" : "chunked";
+ progressCalculator[type](e.loaded, e.total);
+ }
+ };
+ },
+ _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {
+ var xhrsId = optChunkIdx == null ? -1 : optChunkIdx, tempState = handler._getFileState(id).temp;
+ tempState.xhrs = tempState.xhrs || {};
+ tempState.ajaxRequesters = tempState.ajaxRequesters || {};
+ tempState.xhrs[xhrsId] = xhr;
+ if (optAjaxRequester) {
+ tempState.ajaxRequesters[xhrsId] = optAjaxRequester;
+ }
+ return xhr;
+ },
+ _removeExpiredChunkingRecords: function() {
+ var expirationDays = resume.recordsExpireIn;
+ handler._iterateResumeRecords(function(key, uploadData) {
+ var expirationDate = new Date(uploadData.lastUpdated);
+ expirationDate.setDate(expirationDate.getDate() + expirationDays);
+ if (expirationDate.getTime() <= Date.now()) {
+ log("Removing expired resume record with key " + key);
+ localStorage.removeItem(key);
+ }
+ });
+ },
+ _shouldChunkThisFile: function(id) {
+ var state = handler._getFileState(id);
+ if (!state.chunking) {
+ handler.reevaluateChunking(id);
+ }
+ return state.chunking.enabled;
+ }
+ });
+ };
+ qq.DeleteFileAjaxRequester = function(o) {
+ "use strict";
+ var requester, options = {
+ method: "DELETE",
+ uuidParamName: "qquuid",
+ endpointStore: {},
+ maxConnections: 3,
+ customHeaders: function(id) {
+ return {};
+ },
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {}
+ };
+ qq.extend(options, o);
+ function getMandatedParams() {
+ if (options.method.toUpperCase() === "POST") {
+ return {
+ _method: "DELETE"
+ };
+ }
+ return {};
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "POST", "DELETE" ],
+ method: options.method,
+ endpointStore: options.endpointStore,
+ paramsStore: options.paramsStore,
+ mandatedParams: getMandatedParams(),
+ maxConnections: options.maxConnections,
+ customHeaders: function(id) {
+ return options.customHeaders.get(id);
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendDelete: function(id, uuid, additionalMandatedParams) {
+ var additionalOptions = additionalMandatedParams || {};
+ options.log("Submitting delete file request for " + id);
+ if (options.method === "DELETE") {
+ requester.initTransport(id).withPath(uuid).withParams(additionalOptions).send();
+ } else {
+ additionalOptions[options.uuidParamName] = uuid;
+ requester.initTransport(id).withParams(additionalOptions).send();
+ }
+ }
+ });
+ };
+ (function() {
+ function detectSubsampling(img) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, canvas = document.createElement("canvas"), ctx;
+ if (iw * ih > 1024 * 1024) {
+ canvas.width = canvas.height = 1;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, -iw + 1, 0);
+ return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+ } else {
+ return false;
+ }
+ }
+ function detectVerticalSquash(img, iw, ih) {
+ var canvas = document.createElement("canvas"), sy = 0, ey = ih, py = ih, ctx, data, alpha, ratio;
+ canvas.width = 1;
+ canvas.height = ih;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, 0, 0);
+ data = ctx.getImageData(0, 0, 1, ih).data;
+ while (py > sy) {
+ alpha = data[(py - 1) * 4 + 3];
+ if (alpha === 0) {
+ ey = py;
+ } else {
+ sy = py;
+ }
+ py = ey + sy >> 1;
+ }
+ ratio = py / ih;
+ return ratio === 0 ? 1 : ratio;
+ }
+ function renderImageToDataURL(img, blob, options, doSquash) {
+ var canvas = document.createElement("canvas"), mime = options.mime || "image/jpeg", promise = new qq.Promise();
+ renderImageToCanvas(img, blob, canvas, options, doSquash).then(function() {
+ promise.success(canvas.toDataURL(mime, options.quality || .8));
+ });
+ return promise;
+ }
+ function maybeCalculateDownsampledDimensions(spec) {
+ var maxPixels = 5241e3;
+ if (!qq.ios()) {
+ throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");
+ }
+ if (spec.origHeight * spec.origWidth > maxPixels) {
+ return {
+ newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),
+ newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))
+ };
+ }
+ }
+ function renderImageToCanvas(img, blob, canvas, options, doSquash) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, width = options.width, height = options.height, ctx = canvas.getContext("2d"), promise = new qq.Promise(), modifiedDimensions;
+ ctx.save();
+ if (options.resize) {
+ return renderImageToCanvasWithCustomResizer({
+ blob: blob,
+ canvas: canvas,
+ image: img,
+ imageHeight: ih,
+ imageWidth: iw,
+ orientation: options.orientation,
+ resize: options.resize,
+ targetHeight: height,
+ targetWidth: width
+ });
+ }
+ if (!qq.supportedFeatures.unlimitedScaledImageSize) {
+ modifiedDimensions = maybeCalculateDownsampledDimensions({
+ origWidth: width,
+ origHeight: height
+ });
+ if (modifiedDimensions) {
+ qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h", width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight), "warn");
+ width = modifiedDimensions.newWidth;
+ height = modifiedDimensions.newHeight;
+ }
+ }
+ transformCoordinate(canvas, width, height, options.orientation);
+ if (qq.ios()) {
+ (function() {
+ if (detectSubsampling(img)) {
+ iw /= 2;
+ ih /= 2;
+ }
+ var d = 1024, tmpCanvas = document.createElement("canvas"), vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1, dw = Math.ceil(d * width / iw), dh = Math.ceil(d * height / ih / vertSquashRatio), sy = 0, dy = 0, tmpCtx, sx, dx;
+ tmpCanvas.width = tmpCanvas.height = d;
+ tmpCtx = tmpCanvas.getContext("2d");
+ while (sy < ih) {
+ sx = 0;
+ dx = 0;
+ while (sx < iw) {
+ tmpCtx.clearRect(0, 0, d, d);
+ tmpCtx.drawImage(img, -sx, -sy);
+ ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);
+ sx += d;
+ dx += dw;
+ }
+ sy += d;
+ dy += dh;
+ }
+ ctx.restore();
+ tmpCanvas = tmpCtx = null;
+ })();
+ } else {
+ ctx.drawImage(img, 0, 0, width, height);
+ }
+ canvas.qqImageRendered && canvas.qqImageRendered();
+ promise.success();
+ return promise;
+ }
+ function renderImageToCanvasWithCustomResizer(resizeInfo) {
+ var blob = resizeInfo.blob, image = resizeInfo.image, imageHeight = resizeInfo.imageHeight, imageWidth = resizeInfo.imageWidth, orientation = resizeInfo.orientation, promise = new qq.Promise(), resize = resizeInfo.resize, sourceCanvas = document.createElement("canvas"), sourceCanvasContext = sourceCanvas.getContext("2d"), targetCanvas = resizeInfo.canvas, targetHeight = resizeInfo.targetHeight, targetWidth = resizeInfo.targetWidth;
+ transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);
+ targetCanvas.height = targetHeight;
+ targetCanvas.width = targetWidth;
+ sourceCanvasContext.drawImage(image, 0, 0);
+ resize({
+ blob: blob,
+ height: targetHeight,
+ image: image,
+ sourceCanvas: sourceCanvas,
+ targetCanvas: targetCanvas,
+ width: targetWidth
+ }).then(function success() {
+ targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();
+ promise.success();
+ }, promise.failure);
+ return promise;
+ }
+ function transformCoordinate(canvas, width, height, orientation) {
+ switch (orientation) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ canvas.width = height;
+ canvas.height = width;
+ break;
+
+ default:
+ canvas.width = width;
+ canvas.height = height;
+ }
+ var ctx = canvas.getContext("2d");
+ switch (orientation) {
+ case 2:
+ ctx.translate(width, 0);
+ ctx.scale(-1, 1);
+ break;
+
+ case 3:
+ ctx.translate(width, height);
+ ctx.rotate(Math.PI);
+ break;
+
+ case 4:
+ ctx.translate(0, height);
+ ctx.scale(1, -1);
+ break;
+
+ case 5:
+ ctx.rotate(.5 * Math.PI);
+ ctx.scale(1, -1);
+ break;
+
+ case 6:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(0, -height);
+ break;
+
+ case 7:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(width, -height);
+ ctx.scale(-1, 1);
+ break;
+
+ case 8:
+ ctx.rotate(-.5 * Math.PI);
+ ctx.translate(-width, 0);
+ break;
+
+ default:
+ break;
+ }
+ }
+ function MegaPixImage(srcImage, errorCallback) {
+ var self = this;
+ if (window.Blob && srcImage instanceof Blob) {
+ (function() {
+ var img = new Image(), URL = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (!URL) {
+ throw Error("No createObjectURL function found to create blob url");
+ }
+ img.src = URL.createObjectURL(srcImage);
+ self.blob = srcImage;
+ srcImage = img;
+ })();
+ }
+ if (!srcImage.naturalWidth && !srcImage.naturalHeight) {
+ srcImage.onload = function() {
+ var listeners = self.imageLoadListeners;
+ if (listeners) {
+ self.imageLoadListeners = null;
+ setTimeout(function() {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i]();
+ }
+ }, 0);
+ }
+ };
+ srcImage.onerror = errorCallback;
+ this.imageLoadListeners = [];
+ }
+ this.srcImage = srcImage;
+ }
+ MegaPixImage.prototype.render = function(target, options) {
+ options = options || {};
+ var self = this, imgWidth = this.srcImage.naturalWidth, imgHeight = this.srcImage.naturalHeight, width = options.width, height = options.height, maxWidth = options.maxWidth, maxHeight = options.maxHeight, doSquash = !this.blob || this.blob.type === "image/jpeg", tagName = target.tagName.toLowerCase(), opt;
+ if (this.imageLoadListeners) {
+ this.imageLoadListeners.push(function() {
+ self.render(target, options);
+ });
+ return;
+ }
+ if (width && !height) {
+ height = imgHeight * width / imgWidth << 0;
+ } else if (height && !width) {
+ width = imgWidth * height / imgHeight << 0;
+ } else {
+ width = imgWidth;
+ height = imgHeight;
+ }
+ if (maxWidth && width > maxWidth) {
+ width = maxWidth;
+ height = imgHeight * width / imgWidth << 0;
+ }
+ if (maxHeight && height > maxHeight) {
+ height = maxHeight;
+ width = imgWidth * height / imgHeight << 0;
+ }
+ opt = {
+ width: width,
+ height: height
+ }, qq.each(options, function(optionsKey, optionsValue) {
+ opt[optionsKey] = optionsValue;
+ });
+ if (tagName === "img") {
+ (function() {
+ var oldTargetSrc = target.src;
+ renderImageToDataURL(self.srcImage, self.blob, opt, doSquash).then(function(dataUri) {
+ target.src = dataUri;
+ oldTargetSrc === target.src && target.onload();
+ });
+ })();
+ } else if (tagName === "canvas") {
+ renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);
+ }
+ if (typeof this.onrender === "function") {
+ this.onrender(target);
+ }
+ };
+ qq.MegaPixImage = MegaPixImage;
+ })();
+ qq.ImageGenerator = function(log) {
+ "use strict";
+ function isImg(el) {
+ return el.tagName.toLowerCase() === "img";
+ }
+ function isCanvas(el) {
+ return el.tagName.toLowerCase() === "canvas";
+ }
+ function isImgCorsSupported() {
+ return new Image().crossOrigin !== undefined;
+ }
+ function isCanvasSupported() {
+ var canvas = document.createElement("canvas");
+ return canvas.getContext && canvas.getContext("2d");
+ }
+ function determineMimeOfFileName(nameWithPath) {
+ var pathSegments = nameWithPath.split("/"), name = pathSegments[pathSegments.length - 1].split("?")[0], extension = qq.getExtension(name);
+ extension = extension && extension.toLowerCase();
+ switch (extension) {
+ case "jpeg":
+ case "jpg":
+ return "image/jpeg";
+
+ case "png":
+ return "image/png";
+
+ case "bmp":
+ return "image/bmp";
+
+ case "gif":
+ return "image/gif";
+
+ case "tiff":
+ case "tif":
+ return "image/tiff";
+ }
+ }
+ function isCrossOrigin(url) {
+ var targetAnchor = document.createElement("a"), targetProtocol, targetHostname, targetPort;
+ targetAnchor.href = url;
+ targetProtocol = targetAnchor.protocol;
+ targetPort = targetAnchor.port;
+ targetHostname = targetAnchor.hostname;
+ if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {
+ return true;
+ }
+ if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {
+ return true;
+ }
+ if (targetPort !== window.location.port && !qq.ie()) {
+ return true;
+ }
+ return false;
+ }
+ function registerImgLoadListeners(img, promise) {
+ img.onload = function() {
+ img.onload = null;
+ img.onerror = null;
+ promise.success(img);
+ };
+ img.onerror = function() {
+ img.onload = null;
+ img.onerror = null;
+ log("Problem drawing thumbnail!", "error");
+ promise.failure(img, "Problem drawing thumbnail!");
+ };
+ }
+ function registerCanvasDrawImageListener(canvas, promise) {
+ canvas.qqImageRendered = function() {
+ promise.success(canvas);
+ };
+ }
+ function registerThumbnailRenderedListener(imgOrCanvas, promise) {
+ var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);
+ if (isImg(imgOrCanvas)) {
+ registerImgLoadListeners(imgOrCanvas, promise);
+ } else if (isCanvas(imgOrCanvas)) {
+ registerCanvasDrawImageListener(imgOrCanvas, promise);
+ } else {
+ promise.failure(imgOrCanvas);
+ log(qq.format("Element container of type {} is not supported!", imgOrCanvas.tagName), "error");
+ }
+ return registered;
+ }
+ function draw(fileOrBlob, container, options) {
+ var drawPreview = new qq.Promise(), identifier = new qq.Identify(fileOrBlob, log), maxSize = options.maxSize, orient = options.orient == null ? true : options.orient, megapixErrorHandler = function() {
+ container.onerror = null;
+ container.onload = null;
+ log("Could not render preview, file may be too large!", "error");
+ drawPreview.failure(container, "Browser cannot render image!");
+ };
+ identifier.isPreviewable().then(function(mime) {
+ var dummyExif = {
+ parse: function() {
+ return new qq.Promise().success();
+ }
+ }, exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif, mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);
+ if (registerThumbnailRenderedListener(container, drawPreview)) {
+ exif.parse().then(function(exif) {
+ var orientation = exif && exif.Orientation;
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ orientation: orientation,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ }, function(failureMsg) {
+ log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", failureMsg));
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ });
+ }
+ }, function() {
+ log("Not previewable");
+ drawPreview.failure(container, "Not previewable");
+ });
+ return drawPreview;
+ }
+ function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {
+ var tempImg = new Image(), tempImgRender = new qq.Promise();
+ registerThumbnailRenderedListener(tempImg, tempImgRender);
+ if (isCrossOrigin(url)) {
+ tempImg.crossOrigin = "anonymous";
+ }
+ tempImg.src = url;
+ tempImgRender.then(function rendered() {
+ registerThumbnailRenderedListener(canvasOrImg, draw);
+ var mpImg = new qq.MegaPixImage(tempImg);
+ mpImg.render(canvasOrImg, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: determineMimeOfFileName(url),
+ resize: customResizeFunction
+ });
+ }, draw.failure);
+ }
+ function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {
+ registerThumbnailRenderedListener(img, draw);
+ qq(img).css({
+ maxWidth: maxSize + "px",
+ maxHeight: maxSize + "px"
+ });
+ img.src = url;
+ }
+ function drawFromUrl(url, container, options) {
+ var draw = new qq.Promise(), scale = options.scale, maxSize = scale ? options.maxSize : null;
+ if (scale && isImg(container)) {
+ if (isCanvasSupported()) {
+ if (isCrossOrigin(url) && !isImgCorsSupported()) {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ } else {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ }
+ } else {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ }
+ } else if (isCanvas(container)) {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ } else if (registerThumbnailRenderedListener(container, draw)) {
+ container.src = url;
+ }
+ return draw;
+ }
+ qq.extend(this, {
+ generate: function(fileBlobOrUrl, container, options) {
+ if (qq.isString(fileBlobOrUrl)) {
+ log("Attempting to update thumbnail based on server response.");
+ return drawFromUrl(fileBlobOrUrl, container, options || {});
+ } else {
+ log("Attempting to draw client-side image preview.");
+ return draw(fileBlobOrUrl, container, options || {});
+ }
+ }
+ });
+ this._testing = {};
+ this._testing.isImg = isImg;
+ this._testing.isCanvas = isCanvas;
+ this._testing.isCrossOrigin = isCrossOrigin;
+ this._testing.determineMimeOfFileName = determineMimeOfFileName;
+ };
+ qq.Exif = function(fileOrBlob, log) {
+ "use strict";
+ var TAG_IDS = [ 274 ], TAG_INFO = {
+ 274: {
+ name: "Orientation",
+ bytes: 2
+ }
+ };
+ function parseLittleEndian(hex) {
+ var result = 0, pow = 0;
+ while (hex.length > 0) {
+ result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);
+ hex = hex.substring(2, hex.length);
+ pow += 8;
+ }
+ return result;
+ }
+ function seekToApp1(offset, promise) {
+ var theOffset = offset, thePromise = promise;
+ if (theOffset === undefined) {
+ theOffset = 2;
+ thePromise = new qq.Promise();
+ }
+ qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {
+ var match = /^ffe([0-9])/.exec(hex), segmentLength;
+ if (match) {
+ if (match[1] !== "1") {
+ segmentLength = parseInt(hex.slice(4, 8), 16);
+ seekToApp1(theOffset + segmentLength + 2, thePromise);
+ } else {
+ thePromise.success(theOffset);
+ }
+ } else {
+ thePromise.failure("No EXIF header to be found!");
+ }
+ });
+ return thePromise;
+ }
+ function getApp1Offset() {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {
+ if (hex.indexOf("ffd8") !== 0) {
+ promise.failure("Not a valid JPEG!");
+ } else {
+ seekToApp1().then(function(offset) {
+ promise.success(offset);
+ }, function(error) {
+ promise.failure(error);
+ });
+ }
+ });
+ return promise;
+ }
+ function isLittleEndian(app1Start) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {
+ promise.success(hex === "4949");
+ });
+ return promise;
+ }
+ function getDirEntryCount(app1Start, littleEndian) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {
+ if (littleEndian) {
+ return promise.success(parseLittleEndian(hex));
+ } else {
+ promise.success(parseInt(hex, 16));
+ }
+ });
+ return promise;
+ }
+ function getIfd(app1Start, dirEntries) {
+ var offset = app1Start + 20, bytes = dirEntries * 12;
+ return qq.readBlobToHex(fileOrBlob, offset, bytes);
+ }
+ function getDirEntries(ifdHex) {
+ var entries = [], offset = 0;
+ while (offset + 24 <= ifdHex.length) {
+ entries.push(ifdHex.slice(offset, offset + 24));
+ offset += 24;
+ }
+ return entries;
+ }
+ function getTagValues(littleEndian, dirEntries) {
+ var TAG_VAL_OFFSET = 16, tagsToFind = qq.extend([], TAG_IDS), vals = {};
+ qq.each(dirEntries, function(idx, entry) {
+ var idHex = entry.slice(0, 4), id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16), tagsToFindIdx = tagsToFind.indexOf(id), tagValHex, tagName, tagValLength;
+ if (tagsToFindIdx >= 0) {
+ tagName = TAG_INFO[id].name;
+ tagValLength = TAG_INFO[id].bytes;
+ tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + tagValLength * 2);
+ vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);
+ tagsToFind.splice(tagsToFindIdx, 1);
+ }
+ if (tagsToFind.length === 0) {
+ return false;
+ }
+ });
+ return vals;
+ }
+ qq.extend(this, {
+ parse: function() {
+ var parser = new qq.Promise(), onParseFailure = function(message) {
+ log(qq.format("EXIF header parse failed: '{}' ", message));
+ parser.failure(message);
+ };
+ getApp1Offset().then(function(app1Offset) {
+ log(qq.format("Moving forward with EXIF header parsing for '{}'", fileOrBlob.name === undefined ? "blob" : fileOrBlob.name));
+ isLittleEndian(app1Offset).then(function(littleEndian) {
+ log(qq.format("EXIF Byte order is {} endian", littleEndian ? "little" : "big"));
+ getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {
+ log(qq.format("Found {} APP1 directory entries", dirEntryCount));
+ getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {
+ var dirEntries = getDirEntries(ifdHex), tagValues = getTagValues(littleEndian, dirEntries);
+ log("Successfully parsed some EXIF tags");
+ parser.success(tagValues);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ return parser;
+ }
+ });
+ this._testing = {};
+ this._testing.parseLittleEndian = parseLittleEndian;
+ };
+ qq.Identify = function(fileOrBlob, log) {
+ "use strict";
+ function isIdentifiable(magicBytes, questionableBytes) {
+ var identifiable = false, magicBytesEntries = [].concat(magicBytes);
+ qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {
+ if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {
+ identifiable = true;
+ return false;
+ }
+ });
+ return identifiable;
+ }
+ qq.extend(this, {
+ isPreviewable: function() {
+ var self = this, identifier = new qq.Promise(), previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ log(qq.format("Attempting to determine if {} can be rendered in this browser", name));
+ log("First pass: check type attribute of blob object.");
+ if (this.isPreviewableSync()) {
+ log("Second pass: check for magic bytes in file header.");
+ qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {
+ qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {
+ if (isIdentifiable(bytes, hex)) {
+ if (mime !== "image/tiff" || qq.supportedFeatures.tiffPreviews) {
+ previewable = true;
+ identifier.success(mime);
+ }
+ return false;
+ }
+ });
+ log(qq.format("'{}' is {} able to be rendered in this browser", name, previewable ? "" : "NOT"));
+ if (!previewable) {
+ identifier.failure();
+ }
+ }, function() {
+ log("Error reading file w/ name '" + name + "'. Not able to be rendered in this browser.");
+ identifier.failure();
+ });
+ } else {
+ identifier.failure();
+ }
+ return identifier;
+ },
+ isPreviewableSync: function() {
+ var fileMime = fileOrBlob.type, isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0, previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ if (isRecognizedImage) {
+ if (fileMime === "image/tiff") {
+ previewable = qq.supportedFeatures.tiffPreviews;
+ } else {
+ previewable = true;
+ }
+ }
+ !previewable && log(name + " is not previewable in this browser per the blob's type attr");
+ return previewable;
+ }
+ });
+ };
+ qq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {
+ "image/jpeg": "ffd8ff",
+ "image/gif": "474946",
+ "image/png": "89504e",
+ "image/bmp": "424d",
+ "image/tiff": [ "49492a00", "4d4d002a" ]
+ };
+ qq.ImageValidation = function(blob, log) {
+ "use strict";
+ function hasNonZeroLimits(limits) {
+ var atLeastOne = false;
+ qq.each(limits, function(limit, value) {
+ if (value > 0) {
+ atLeastOne = true;
+ return false;
+ }
+ });
+ return atLeastOne;
+ }
+ function getWidthHeight() {
+ var sizeDetermination = new qq.Promise();
+ new qq.Identify(blob, log).isPreviewable().then(function() {
+ var image = new Image(), url = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (url) {
+ image.onerror = function() {
+ log("Cannot determine dimensions for image. May be too large.", "error");
+ sizeDetermination.failure();
+ };
+ image.onload = function() {
+ sizeDetermination.success({
+ width: this.width,
+ height: this.height
+ });
+ };
+ image.src = url.createObjectURL(blob);
+ } else {
+ log("No createObjectURL function available to generate image URL!", "error");
+ sizeDetermination.failure();
+ }
+ }, sizeDetermination.failure);
+ return sizeDetermination;
+ }
+ function getFailingLimit(limits, dimensions) {
+ var failingLimit;
+ qq.each(limits, function(limitName, limitValue) {
+ if (limitValue > 0) {
+ var limitMatcher = /(max|min)(Width|Height)/.exec(limitName), dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1), actualValue = dimensions[dimensionPropName];
+ switch (limitMatcher[1]) {
+ case "min":
+ if (actualValue < limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+
+ case "max":
+ if (actualValue > limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+ }
+ }
+ });
+ return failingLimit;
+ }
+ this.validate = function(limits) {
+ var validationEffort = new qq.Promise();
+ log("Attempting to validate image.");
+ if (hasNonZeroLimits(limits)) {
+ getWidthHeight().then(function(dimensions) {
+ var failingLimit = getFailingLimit(limits, dimensions);
+ if (failingLimit) {
+ validationEffort.failure(failingLimit);
+ } else {
+ validationEffort.success();
+ }
+ }, validationEffort.success);
+ } else {
+ validationEffort.success();
+ }
+ return validationEffort;
+ };
+ };
+ qq.Session = function(spec) {
+ "use strict";
+ var options = {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ cors: {},
+ addFileRecord: function(sessionData) {},
+ log: function(message, level) {}
+ };
+ qq.extend(options, spec, true);
+ function isJsonResponseValid(response) {
+ if (qq.isArray(response)) {
+ return true;
+ }
+ options.log("Session response is not an array.", "error");
+ }
+ function handleFileItems(fileItems, success, xhrOrXdr, promise) {
+ var someItemsIgnored = false;
+ success = success && isJsonResponseValid(fileItems);
+ if (success) {
+ qq.each(fileItems, function(idx, fileItem) {
+ if (fileItem.uuid == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid UUID - ignoring.", idx), "error");
+ } else if (fileItem.name == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid name - ignoring.", idx), "error");
+ } else {
+ try {
+ options.addFileRecord(fileItem);
+ return true;
+ } catch (err) {
+ someItemsIgnored = true;
+ options.log(err.message, "error");
+ }
+ }
+ return false;
+ });
+ }
+ promise[success && !someItemsIgnored ? "success" : "failure"](fileItems, xhrOrXdr);
+ }
+ this.refresh = function() {
+ var refreshEffort = new qq.Promise(), refreshCompleteCallback = function(response, success, xhrOrXdr) {
+ handleFileItems(response, success, xhrOrXdr, refreshEffort);
+ }, requesterOptions = qq.extend({}, options), requester = new qq.SessionAjaxRequester(qq.extend(requesterOptions, {
+ onComplete: refreshCompleteCallback
+ }));
+ requester.queryServer();
+ return refreshEffort;
+ };
+ };
+ qq.SessionAjaxRequester = function(spec) {
+ "use strict";
+ var requester, options = {
+ endpoint: null,
+ customHeaders: {},
+ params: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ onComplete: function(response, success, xhrOrXdr) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, spec);
+ function onComplete(id, xhrOrXdr, isError) {
+ var response = null;
+ if (xhrOrXdr.responseText != null) {
+ try {
+ response = qq.parseJson(xhrOrXdr.responseText);
+ } catch (err) {
+ options.log("Problem parsing session response: " + err.message, "error");
+ isError = true;
+ }
+ }
+ options.onComplete(response, !isError, xhrOrXdr);
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: onComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ queryServer: function() {
+ var params = qq.extend({}, options.params);
+ options.log("Session query request.");
+ requester.initTransport("sessionRefresh").withParams(params).withCacheBuster().send();
+ }
+ });
+ };
+ qq.Scaler = function(spec, log) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizer, includeOriginal = spec.sendOriginal, orient = spec.orient, defaultType = spec.defaultType, defaultQuality = spec.defaultQuality / 100, failedToScaleText = spec.failureText, includeExif = spec.includeExif, sizes = this._getSortedSizes(spec.sizes);
+ qq.extend(this, {
+ enabled: qq.supportedFeatures.scaling && sizes.length > 0,
+ getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {
+ var self = this, records = [], originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData, identifier = new qq.Identify(originalBlob, log);
+ if (identifier.isPreviewableSync()) {
+ qq.each(sizes, function(idx, sizeRecord) {
+ var outputType = self._determineOutputType({
+ defaultType: defaultType,
+ requestedType: sizeRecord.type,
+ refType: originalBlob.type
+ });
+ records.push({
+ uuid: qq.getUniqueId(),
+ name: self._getName(originalFileName, {
+ name: sizeRecord.name,
+ type: outputType,
+ refType: originalBlob.type
+ }),
+ blob: new qq.BlobProxy(originalBlob, qq.bind(self._generateScaledImage, self, {
+ customResizeFunction: customResizeFunction,
+ maxSize: sizeRecord.maxSize,
+ orient: orient,
+ type: outputType,
+ quality: defaultQuality,
+ failedText: failedToScaleText,
+ includeExif: includeExif,
+ log: log
+ }))
+ });
+ });
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: includeOriginal ? originalBlob : null
+ });
+ } else {
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: originalBlob
+ });
+ }
+ return records;
+ },
+ handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {
+ var self = this, buttonId = file.qqButtonId || file.blob && file.blob.qqButtonId, scaledIds = [], originalId = null, addFileToHandler = api.addFileToHandler, uploadData = api.uploadData, paramsStore = api.paramsStore, proxyGroupId = qq.getUniqueId();
+ qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {
+ var blobSize = record.size, id;
+ if (record.blob instanceof qq.BlobProxy) {
+ blobSize = -1;
+ }
+ id = uploadData.addFile({
+ uuid: record.uuid,
+ name: record.name,
+ size: blobSize,
+ batchId: batchId,
+ proxyGroupId: proxyGroupId
+ });
+ if (record.blob instanceof qq.BlobProxy) {
+ scaledIds.push(id);
+ } else {
+ originalId = id;
+ }
+ if (record.blob) {
+ addFileToHandler(id, record.blob);
+ fileList.push({
+ id: id,
+ file: record.blob
+ });
+ } else {
+ uploadData.setStatus(id, qq.status.REJECTED);
+ }
+ });
+ if (originalId !== null) {
+ qq.each(scaledIds, function(idx, scaledId) {
+ var params = {
+ qqparentuuid: uploadData.retrieve({
+ id: originalId
+ }).uuid,
+ qqparentsize: uploadData.retrieve({
+ id: originalId
+ }).size
+ };
+ params[uuidParamName] = uploadData.retrieve({
+ id: scaledId
+ }).uuid;
+ uploadData.setParentId(scaledId, originalId);
+ paramsStore.addReadOnly(scaledId, params);
+ });
+ if (scaledIds.length) {
+ (function() {
+ var param = {};
+ param[uuidParamName] = uploadData.retrieve({
+ id: originalId
+ }).uuid;
+ paramsStore.addReadOnly(originalId, param);
+ })();
+ }
+ }
+ }
+ });
+ };
+ qq.extend(qq.Scaler.prototype, {
+ scaleImage: function(id, specs, api) {
+ "use strict";
+ if (!qq.supportedFeatures.scaling) {
+ throw new qq.Error("Scaling is not supported in this browser!");
+ }
+ var scalingEffort = new qq.Promise(), log = api.log, file = api.getFile(id), uploadData = api.uploadData.retrieve({
+ id: id
+ }), name = uploadData && uploadData.name, uuid = uploadData && uploadData.uuid, scalingOptions = {
+ customResizer: specs.customResizer,
+ sendOriginal: false,
+ orient: specs.orient,
+ defaultType: specs.type || null,
+ defaultQuality: specs.quality,
+ failedToScaleText: "Unable to scale",
+ sizes: [ {
+ name: "",
+ maxSize: specs.maxSize
+ } ]
+ }, scaler = new qq.Scaler(scalingOptions, log);
+ if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {
+ scalingEffort.failure();
+ log("Could not generate requested scaled image for " + id + ". " + "Scaling is either not possible in this browser, or the file could not be located.", "error");
+ } else {
+ qq.bind(function() {
+ var record = scaler.getFileRecords(uuid, name, file)[0];
+ if (record && record.blob instanceof qq.BlobProxy) {
+ record.blob.create().then(scalingEffort.success, scalingEffort.failure);
+ } else {
+ log(id + " is not a scalable image!", "error");
+ scalingEffort.failure();
+ }
+ }, this)();
+ }
+ return scalingEffort;
+ },
+ _determineOutputType: function(spec) {
+ "use strict";
+ var requestedType = spec.requestedType, defaultType = spec.defaultType, referenceType = spec.refType;
+ if (!defaultType && !requestedType) {
+ if (referenceType !== "image/jpeg") {
+ return "image/png";
+ }
+ return referenceType;
+ }
+ if (!requestedType) {
+ return defaultType;
+ }
+ if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {
+ if (requestedType === "image/tiff") {
+ return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;
+ }
+ return requestedType;
+ }
+ return defaultType;
+ },
+ _getName: function(originalName, scaledVersionProperties) {
+ "use strict";
+ var startOfExt = originalName.lastIndexOf("."), versionType = scaledVersionProperties.type || "image/png", referenceType = scaledVersionProperties.refType, scaledName = "", scaledExt = qq.getExtension(originalName), nameAppendage = "";
+ if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {
+ nameAppendage = " (" + scaledVersionProperties.name + ")";
+ }
+ if (startOfExt >= 0) {
+ scaledName = originalName.substr(0, startOfExt);
+ if (referenceType !== versionType) {
+ scaledExt = versionType.split("/")[1];
+ }
+ scaledName += nameAppendage + "." + scaledExt;
+ } else {
+ scaledName = originalName + nameAppendage;
+ }
+ return scaledName;
+ },
+ _getSortedSizes: function(sizes) {
+ "use strict";
+ sizes = qq.extend([], sizes);
+ return sizes.sort(function(a, b) {
+ if (a.maxSize > b.maxSize) {
+ return 1;
+ }
+ if (a.maxSize < b.maxSize) {
+ return -1;
+ }
+ return 0;
+ });
+ },
+ _generateScaledImage: function(spec, sourceFile) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizeFunction, log = spec.log, maxSize = spec.maxSize, orient = spec.orient, type = spec.type, quality = spec.quality, failedText = spec.failedText, includeExif = spec.includeExif && sourceFile.type === "image/jpeg" && type === "image/jpeg", scalingEffort = new qq.Promise(), imageGenerator = new qq.ImageGenerator(log), canvas = document.createElement("canvas");
+ log("Attempting to generate scaled version for " + sourceFile.name);
+ imageGenerator.generate(sourceFile, canvas, {
+ maxSize: maxSize,
+ orient: orient,
+ customResizeFunction: customResizeFunction
+ }).then(function() {
+ var scaledImageDataUri = canvas.toDataURL(type, quality), signalSuccess = function() {
+ log("Success generating scaled version for " + sourceFile.name);
+ var blob = qq.dataUriToBlob(scaledImageDataUri);
+ scalingEffort.success(blob);
+ };
+ if (includeExif) {
+ self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {
+ scaledImageDataUri = scaledImageDataUriWithExif;
+ signalSuccess();
+ }, function() {
+ log("Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.", "error");
+ signalSuccess();
+ });
+ } else {
+ signalSuccess();
+ }
+ }, function() {
+ log("Failed attempt to generate scaled version for " + sourceFile.name, "error");
+ scalingEffort.failure(failedText);
+ });
+ return scalingEffort;
+ },
+ _insertExifHeader: function(originalImage, scaledImageDataUri, log) {
+ "use strict";
+ var reader = new FileReader(), insertionEffort = new qq.Promise(), originalImageDataUri = "";
+ reader.onload = function() {
+ originalImageDataUri = reader.result;
+ insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));
+ };
+ reader.onerror = function() {
+ log("Problem reading " + originalImage.name + " during attempt to transfer EXIF data to scaled version.", "error");
+ insertionEffort.failure();
+ };
+ reader.readAsDataURL(originalImage);
+ return insertionEffort;
+ },
+ _dataUriToBlob: function(dataUri) {
+ "use strict";
+ var byteString, mimeString, arrayBuffer, intArray;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return this._createBlob(arrayBuffer, mimeString);
+ },
+ _createBlob: function(data, mime) {
+ "use strict";
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }
+ });
+ qq.ExifRestorer = function() {
+ var ExifRestorer = {};
+ ExifRestorer.KEY_STR = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + "ghijklmnopqrstuv" + "wxyz0123456789+/" + "=";
+ ExifRestorer.encode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0;
+ do {
+ chr1 = input[i++];
+ chr2 = input[i++];
+ chr3 = input[i++];
+ enc1 = chr1 >> 2;
+ enc2 = (chr1 & 3) << 4 | chr2 >> 4;
+ enc3 = (chr2 & 15) << 2 | chr3 >> 6;
+ enc4 = chr3 & 63;
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+ output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4);
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return output;
+ };
+ ExifRestorer.restore = function(origFileBase64, resizedFileBase64) {
+ var expectedBase64Header = "data:image/jpeg;base64,";
+ if (!origFileBase64.match(expectedBase64Header)) {
+ return resizedFileBase64;
+ }
+ var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, ""));
+ var segments = this.slice2Segments(rawImage);
+ var image = this.exifManipulation(resizedFileBase64, segments);
+ return expectedBase64Header + this.encode64(image);
+ };
+ ExifRestorer.exifManipulation = function(resizedFileBase64, segments) {
+ var exifArray = this.getExifArray(segments), newImageArray = this.insertExif(resizedFileBase64, exifArray), aBuffer = new Uint8Array(newImageArray);
+ return aBuffer;
+ };
+ ExifRestorer.getExifArray = function(segments) {
+ var seg;
+ for (var x = 0; x < segments.length; x++) {
+ seg = segments[x];
+ if (seg[0] == 255 & seg[1] == 225) {
+ return seg;
+ }
+ }
+ return [];
+ };
+ ExifRestorer.insertExif = function(resizedFileBase64, exifArray) {
+ var imageData = resizedFileBase64.replace("data:image/jpeg;base64,", ""), buf = this.decode64(imageData), separatePoint = buf.indexOf(255, 3), mae = buf.slice(0, separatePoint), ato = buf.slice(separatePoint), array = mae;
+ array = array.concat(exifArray);
+ array = array.concat(ato);
+ return array;
+ };
+ ExifRestorer.slice2Segments = function(rawImageArray) {
+ var head = 0, segments = [];
+ while (1) {
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218) {
+ break;
+ }
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216) {
+ head += 2;
+ } else {
+ var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3], endPoint = head + length + 2, seg = rawImageArray.slice(head, endPoint);
+ segments.push(seg);
+ head = endPoint;
+ }
+ if (head > rawImageArray.length) {
+ break;
+ }
+ }
+ return segments;
+ };
+ ExifRestorer.decode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0, buf = [];
+ var base64test = /[^A-Za-z0-9\+\/\=]/g;
+ if (base64test.exec(input)) {
+ throw new Error("There were invalid base64 characters in the input text. " + "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");
+ }
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+ do {
+ enc1 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc2 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc3 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc4 = this.KEY_STR.indexOf(input.charAt(i++));
+ chr1 = enc1 << 2 | enc2 >> 4;
+ chr2 = (enc2 & 15) << 4 | enc3 >> 2;
+ chr3 = (enc3 & 3) << 6 | enc4;
+ buf.push(chr1);
+ if (enc3 != 64) {
+ buf.push(chr2);
+ }
+ if (enc4 != 64) {
+ buf.push(chr3);
+ }
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return buf;
+ };
+ return ExifRestorer;
+ }();
+ qq.TotalProgress = function(callback, getSize) {
+ "use strict";
+ var perFileProgress = {}, totalLoaded = 0, totalSize = 0, lastLoadedSent = -1, lastTotalSent = -1, callbackProxy = function(loaded, total) {
+ if (loaded !== lastLoadedSent || total !== lastTotalSent) {
+ callback(loaded, total);
+ }
+ lastLoadedSent = loaded;
+ lastTotalSent = total;
+ }, noRetryableFiles = function(failed, retryable) {
+ var none = true;
+ qq.each(failed, function(idx, failedId) {
+ if (qq.indexOf(retryable, failedId) >= 0) {
+ none = false;
+ return false;
+ }
+ });
+ return none;
+ }, onCancel = function(id) {
+ updateTotalProgress(id, -1, -1);
+ delete perFileProgress[id];
+ }, onAllComplete = function(successful, failed, retryable) {
+ if (failed.length === 0 || noRetryableFiles(failed, retryable)) {
+ callbackProxy(totalSize, totalSize);
+ this.reset();
+ }
+ }, onNew = function(id) {
+ var size = getSize(id);
+ if (size > 0) {
+ updateTotalProgress(id, 0, size);
+ perFileProgress[id] = {
+ loaded: 0,
+ total: size
+ };
+ }
+ }, updateTotalProgress = function(id, newLoaded, newTotal) {
+ var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0, oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;
+ if (newLoaded === -1 && newTotal === -1) {
+ totalLoaded -= oldLoaded;
+ totalSize -= oldTotal;
+ } else {
+ if (newLoaded) {
+ totalLoaded += newLoaded - oldLoaded;
+ }
+ if (newTotal) {
+ totalSize += newTotal - oldTotal;
+ }
+ }
+ callbackProxy(totalLoaded, totalSize);
+ };
+ qq.extend(this, {
+ onAllComplete: onAllComplete,
+ onStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {
+ onCancel(id);
+ } else if (newStatus === qq.status.SUBMITTING) {
+ onNew(id);
+ }
+ },
+ onIndividualProgress: function(id, loaded, total) {
+ updateTotalProgress(id, loaded, total);
+ perFileProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onNewSize: function(id) {
+ onNew(id);
+ },
+ reset: function() {
+ perFileProgress = {};
+ totalLoaded = 0;
+ totalSize = 0;
+ }
+ });
+ };
+ qq.PasteSupport = function(o) {
+ "use strict";
+ var options, detachPasteHandler;
+ options = {
+ targetElement: null,
+ callbacks: {
+ log: function(message, level) {},
+ pasteReceived: function(blob) {}
+ }
+ };
+ function isImage(item) {
+ return item.type && item.type.indexOf("image/") === 0;
+ }
+ function registerPasteHandler() {
+ detachPasteHandler = qq(options.targetElement).attach("paste", function(event) {
+ var clipboardData = event.clipboardData;
+ if (clipboardData) {
+ qq.each(clipboardData.items, function(idx, item) {
+ if (isImage(item)) {
+ var blob = item.getAsFile();
+ options.callbacks.pasteReceived(blob);
+ }
+ });
+ }
+ });
+ }
+ function unregisterPasteHandler() {
+ if (detachPasteHandler) {
+ detachPasteHandler();
+ }
+ }
+ qq.extend(options, o);
+ registerPasteHandler();
+ qq.extend(this, {
+ reset: function() {
+ unregisterPasteHandler();
+ }
+ });
+ };
+ qq.FormSupport = function(options, startUpload, log) {
+ "use strict";
+ var self = this, interceptSubmit = options.interceptSubmit, formEl = options.element, autoUpload = options.autoUpload;
+ qq.extend(this, {
+ newEndpoint: null,
+ newAutoUpload: autoUpload,
+ attachedToForm: false,
+ getFormInputsAsObject: function() {
+ if (formEl == null) {
+ return null;
+ }
+ return self._form2Obj(formEl);
+ }
+ });
+ function determineNewEndpoint(formEl) {
+ if (formEl.getAttribute("action")) {
+ self.newEndpoint = formEl.getAttribute("action");
+ }
+ }
+ function validateForm(formEl, nativeSubmit) {
+ if (formEl.checkValidity && !formEl.checkValidity()) {
+ log("Form did not pass validation checks - will not upload.", "error");
+ nativeSubmit();
+ } else {
+ return true;
+ }
+ }
+ function maybeUploadOnSubmit(formEl) {
+ var nativeSubmit = formEl.submit;
+ qq(formEl).attach("submit", function(event) {
+ event = event || window.event;
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
+ validateForm(formEl, nativeSubmit) && startUpload();
+ });
+ formEl.submit = function() {
+ validateForm(formEl, nativeSubmit) && startUpload();
+ };
+ }
+ function determineFormEl(formEl) {
+ if (formEl) {
+ if (qq.isString(formEl)) {
+ formEl = document.getElementById(formEl);
+ }
+ if (formEl) {
+ log("Attaching to form element.");
+ determineNewEndpoint(formEl);
+ interceptSubmit && maybeUploadOnSubmit(formEl);
+ }
+ }
+ return formEl;
+ }
+ formEl = determineFormEl(formEl);
+ this.attachedToForm = !!formEl;
+ };
+ qq.extend(qq.FormSupport.prototype, {
+ _form2Obj: function(form) {
+ "use strict";
+ var obj = {}, notIrrelevantType = function(type) {
+ var irrelevantTypes = [ "button", "image", "reset", "submit" ];
+ return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;
+ }, radioOrCheckbox = function(type) {
+ return qq.indexOf([ "checkbox", "radio" ], type.toLowerCase()) >= 0;
+ }, ignoreValue = function(el) {
+ if (radioOrCheckbox(el.type) && !el.checked) {
+ return true;
+ }
+ return el.disabled && el.type.toLowerCase() !== "hidden";
+ }, selectValue = function(select) {
+ var value = null;
+ qq.each(qq(select).children(), function(idx, child) {
+ if (child.tagName.toLowerCase() === "option" && child.selected) {
+ value = child.value;
+ return false;
+ }
+ });
+ return value;
+ };
+ qq.each(form.elements, function(idx, el) {
+ if ((qq.isInput(el, true) || el.tagName.toLowerCase() === "textarea") && notIrrelevantType(el.type) && !ignoreValue(el)) {
+ obj[el.name] = el.value;
+ } else if (el.tagName.toLowerCase() === "select" && !ignoreValue(el)) {
+ var value = selectValue(el);
+ if (value !== null) {
+ obj[el.name] = value;
+ }
+ }
+ });
+ return obj;
+ }
+ });
+ qq.traditional = qq.traditional || {};
+ qq.traditional.FormUploadHandler = function(options, proxy) {
+ "use strict";
+ var handler = this, getName = proxy.getName, getUuid = proxy.getUuid, log = proxy.log;
+ function getIframeContentJson(id, iframe) {
+ var response, doc, innerHtml;
+ try {
+ doc = iframe.contentDocument || iframe.contentWindow.document;
+ innerHtml = doc.body.innerHTML;
+ log("converting iframe's innerHTML to JSON");
+ log("innerHTML = " + innerHtml);
+ if (innerHtml && innerHtml.match(/^ 1 && !options.allowMultipleItems) {
+ options.callbacks.processingDroppedFilesComplete([]);
+ options.callbacks.dropError("tooManyFilesError", "");
+ uploadDropZone.dropDisabled(false);
+ handleDataTransferPromise.failure();
+ } else {
+ droppedFiles = [];
+ if (qq.isFolderDropSupported(dataTransfer)) {
+ qq.each(dataTransfer.items, function(idx, item) {
+ var entry = item.webkitGetAsEntry();
+ if (entry) {
+ if (entry.isFile) {
+ droppedFiles.push(item.getAsFile());
+ } else {
+ pendingFolderPromises.push(traverseFileTree(entry).done(function() {
+ pendingFolderPromises.pop();
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }));
+ }
+ }
+ });
+ } else {
+ droppedFiles = dataTransfer.files;
+ }
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }
+ return handleDataTransferPromise;
+ }
+ function setupDropzone(dropArea) {
+ var dropZone = new qq.UploadDropZone({
+ HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,
+ element: dropArea,
+ onEnter: function(e) {
+ qq(dropArea).addClass(options.classes.dropActive);
+ e.stopPropagation();
+ },
+ onLeaveNotDescendants: function(e) {
+ qq(dropArea).removeClass(options.classes.dropActive);
+ },
+ onDrop: function(e) {
+ handleDataTransfer(e.dataTransfer, dropZone).then(function() {
+ uploadDroppedFiles(droppedFiles, dropZone);
+ }, function() {
+ options.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.", "error");
+ });
+ }
+ });
+ disposeSupport.addDisposer(function() {
+ dropZone.dispose();
+ });
+ qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();
+ uploadDropZones.push(dropZone);
+ return dropZone;
+ }
+ function isFileDrag(dragEvent) {
+ var fileDrag;
+ qq.each(dragEvent.dataTransfer.types, function(key, val) {
+ if (val === "Files") {
+ fileDrag = true;
+ return false;
+ }
+ });
+ return fileDrag;
+ }
+ function leavingDocumentOut(e) {
+ if (qq.firefox()) {
+ return !e.relatedTarget;
+ }
+ if (qq.safari()) {
+ return e.x < 0 || e.y < 0;
+ }
+ return e.x === 0 && e.y === 0;
+ }
+ function setupDragDrop() {
+ var dropZones = options.dropZoneElements, maybeHideDropZones = function() {
+ setTimeout(function() {
+ qq.each(dropZones, function(idx, dropZone) {
+ qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();
+ qq(dropZone).removeClass(options.classes.dropActive);
+ });
+ }, 10);
+ };
+ qq.each(dropZones, function(idx, dropZone) {
+ var uploadDropZone = setupDropzone(dropZone);
+ if (dropZones.length && qq.supportedFeatures.fileDrop) {
+ disposeSupport.attach(document, "dragenter", function(e) {
+ if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {
+ qq.each(dropZones, function(idx, dropZone) {
+ if (dropZone instanceof HTMLElement && qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {
+ qq(dropZone).css({
+ display: "block"
+ });
+ }
+ });
+ }
+ });
+ }
+ });
+ disposeSupport.attach(document, "dragleave", function(e) {
+ if (leavingDocumentOut(e)) {
+ maybeHideDropZones();
+ }
+ });
+ disposeSupport.attach(qq(document).children()[0], "mouseenter", function(e) {
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, "drop", function(e) {
+ e.preventDefault();
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);
+ }
+ setupDragDrop();
+ qq.extend(this, {
+ setupExtraDropzone: function(element) {
+ options.dropZoneElements.push(element);
+ setupDropzone(element);
+ },
+ removeDropzone: function(element) {
+ var i, dzs = options.dropZoneElements;
+ for (i in dzs) {
+ if (dzs[i] === element) {
+ return dzs.splice(i, 1);
+ }
+ }
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ qq.each(uploadDropZones, function(idx, dropZone) {
+ dropZone.dispose();
+ });
+ }
+ });
+ };
+ qq.DragAndDrop.callbacks = function() {
+ "use strict";
+ return {
+ processingDroppedFiles: function() {},
+ processingDroppedFilesComplete: function(files, targetEl) {},
+ dropError: function(code, errorSpecifics) {
+ qq.log("Drag & drop error code '" + code + " with these specifics: '" + errorSpecifics + "'", "error");
+ },
+ dropLog: function(message, level) {
+ qq.log(message, level);
+ }
+ };
+ };
+ qq.UploadDropZone = function(o) {
+ "use strict";
+ var disposeSupport = new qq.DisposeSupport(), options, element, preventDrop, dropOutsideDisabled;
+ options = {
+ element: null,
+ onEnter: function(e) {},
+ onLeave: function(e) {},
+ onLeaveNotDescendants: function(e) {},
+ onDrop: function(e) {}
+ };
+ qq.extend(options, o);
+ element = options.element;
+ function dragoverShouldBeCanceled() {
+ return qq.safari() || qq.firefox() && qq.windows();
+ }
+ function disableDropOutside(e) {
+ if (!dropOutsideDisabled) {
+ if (dragoverShouldBeCanceled) {
+ disposeSupport.attach(document, "dragover", function(e) {
+ e.preventDefault();
+ });
+ } else {
+ disposeSupport.attach(document, "dragover", function(e) {
+ if (e.dataTransfer) {
+ e.dataTransfer.dropEffect = "none";
+ e.preventDefault();
+ }
+ });
+ }
+ dropOutsideDisabled = true;
+ }
+ }
+ function isValidFileDrag(e) {
+ if (!qq.supportedFeatures.fileDrop) {
+ return false;
+ }
+ var effectTest, dt = e.dataTransfer, isSafari = qq.safari();
+ effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== "none";
+ return dt && effectTest && (dt.files || !isSafari && dt.types.contains && dt.types.contains("Files"));
+ }
+ function isOrSetDropDisabled(isDisabled) {
+ if (isDisabled !== undefined) {
+ preventDrop = isDisabled;
+ }
+ return preventDrop;
+ }
+ function triggerHidezonesEvent() {
+ var hideZonesEvent;
+ function triggerUsingOldApi() {
+ hideZonesEvent = document.createEvent("Event");
+ hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);
+ }
+ if (window.CustomEvent) {
+ try {
+ hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);
+ } catch (err) {
+ triggerUsingOldApi();
+ }
+ } else {
+ triggerUsingOldApi();
+ }
+ document.dispatchEvent(hideZonesEvent);
+ }
+ function attachEvents() {
+ disposeSupport.attach(element, "dragover", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;
+ if (effect === "move" || effect === "linkMove") {
+ e.dataTransfer.dropEffect = "move";
+ } else {
+ e.dataTransfer.dropEffect = "copy";
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ disposeSupport.attach(element, "dragenter", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onEnter(e);
+ }
+ });
+ disposeSupport.attach(element, "dragleave", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onLeave(e);
+ var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
+ if (qq(this).contains(relatedTarget)) {
+ return;
+ }
+ options.onLeaveNotDescendants(e);
+ });
+ disposeSupport.attach(element, "drop", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ options.onDrop(e);
+ triggerHidezonesEvent();
+ }
+ });
+ }
+ disableDropOutside();
+ attachEvents();
+ qq.extend(this, {
+ dropDisabled: function(isDisabled) {
+ return isOrSetDropDisabled(isDisabled);
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ },
+ getElement: function() {
+ return element;
+ }
+ });
+ };
+ (function() {
+ "use strict";
+ qq.uiPublicApi = {
+ addInitialFiles: function(cannedFileList) {
+ this._parent.prototype.addInitialFiles.apply(this, arguments);
+ this._templating.addCacheToDom();
+ },
+ clearStoredFiles: function() {
+ this._parent.prototype.clearStoredFiles.apply(this, arguments);
+ this._templating.clearFiles();
+ },
+ addExtraDropzone: function(element) {
+ this._dnd && this._dnd.setupExtraDropzone(element);
+ },
+ removeExtraDropzone: function(element) {
+ if (this._dnd) {
+ return this._dnd.removeDropzone(element);
+ }
+ },
+ getItemByFileId: function(id) {
+ if (!this._templating.isHiddenForever(id)) {
+ return this._templating.getFileContainer(id);
+ }
+ },
+ reset: function() {
+ this._parent.prototype.reset.apply(this, arguments);
+ this._templating.reset();
+ if (!this._options.button && this._templating.getButton()) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._templating.getButton(),
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ if (this._dnd) {
+ this._dnd.dispose();
+ this._dnd = this._setupDragAndDrop();
+ }
+ this._totalFilesInBatch = 0;
+ this._filesInBatchAddedToUi = 0;
+ this._setupClickAndEditEventHandlers();
+ },
+ setName: function(id, newName) {
+ var formattedFilename = this._options.formatFileName(newName);
+ this._parent.prototype.setName.apply(this, arguments);
+ this._templating.updateFilename(id, formattedFilename);
+ },
+ pauseUpload: function(id) {
+ var paused = this._parent.prototype.pauseUpload.apply(this, arguments);
+ paused && this._templating.uploadPaused(id);
+ return paused;
+ },
+ continueUpload: function(id) {
+ var continued = this._parent.prototype.continueUpload.apply(this, arguments);
+ continued && this._templating.uploadContinued(id);
+ return continued;
+ },
+ getId: function(fileContainerOrChildEl) {
+ return this._templating.getFileId(fileContainerOrChildEl);
+ },
+ getDropTarget: function(fileId) {
+ var file = this.getFile(fileId);
+ return file.qqDropTarget;
+ }
+ };
+ qq.uiPrivateApi = {
+ _getButton: function(buttonId) {
+ var button = this._parent.prototype._getButton.apply(this, arguments);
+ if (!button) {
+ if (buttonId === this._defaultButtonId) {
+ button = this._templating.getButton();
+ }
+ }
+ return button;
+ },
+ _removeFileItem: function(fileId) {
+ this._templating.removeFile(fileId);
+ },
+ _setupClickAndEditEventHandlers: function() {
+ this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();
+ this._focusinEventSupported = !qq.firefox();
+ if (this._isEditFilenameEnabled()) {
+ this._filenameClickHandler = this._bindFilenameClickEvent();
+ this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();
+ this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();
+ }
+ },
+ _setupDragAndDrop: function() {
+ var self = this, dropZoneElements = this._options.dragAndDrop.extraDropzones, templating = this._templating, defaultDropZone = templating.getDropZone();
+ defaultDropZone && dropZoneElements.push(defaultDropZone);
+ return new qq.DragAndDrop({
+ dropZoneElements: dropZoneElements,
+ allowMultipleItems: this._options.multiple,
+ classes: {
+ dropActive: this._options.classes.dropActive
+ },
+ callbacks: {
+ processingDroppedFiles: function() {
+ templating.showDropProcessing();
+ },
+ processingDroppedFilesComplete: function(files, targetEl) {
+ templating.hideDropProcessing();
+ qq.each(files, function(idx, file) {
+ file.qqDropTarget = targetEl;
+ });
+ if (files.length) {
+ self.addFiles(files, null, null);
+ }
+ },
+ dropError: function(code, errorData) {
+ self._itemError(code, errorData);
+ },
+ dropLog: function(message, level) {
+ self.log(message, level);
+ }
+ }
+ });
+ },
+ _bindFileButtonsClickEvent: function() {
+ var self = this;
+ return new qq.FileButtonsClickHandler({
+ templating: this._templating,
+ log: function(message, lvl) {
+ self.log(message, lvl);
+ },
+ onDeleteFile: function(fileId) {
+ self.deleteFile(fileId);
+ },
+ onCancel: function(fileId) {
+ self.cancel(fileId);
+ },
+ onRetry: function(fileId) {
+ self.retry(fileId);
+ },
+ onPause: function(fileId) {
+ self.pauseUpload(fileId);
+ },
+ onContinue: function(fileId) {
+ self.continueUpload(fileId);
+ },
+ onGetName: function(fileId) {
+ return self.getName(fileId);
+ }
+ });
+ },
+ _isEditFilenameEnabled: function() {
+ return this._templating.isEditFilenamePossible() && !this._options.autoUpload && qq.FilenameClickHandler && qq.FilenameInputFocusHandler && qq.FilenameInputFocusHandler;
+ },
+ _filenameEditHandler: function() {
+ var self = this, templating = this._templating;
+ return {
+ templating: templating,
+ log: function(message, lvl) {
+ self.log(message, lvl);
+ },
+ onGetUploadStatus: function(fileId) {
+ return self.getUploads({
+ id: fileId
+ }).status;
+ },
+ onGetName: function(fileId) {
+ return self.getName(fileId);
+ },
+ onSetName: function(id, newName) {
+ self.setName(id, newName);
+ },
+ onEditingStatusChange: function(id, isEditing) {
+ var qqInput = qq(templating.getEditInput(id)), qqFileContainer = qq(templating.getFileContainer(id));
+ if (isEditing) {
+ qqInput.addClass("qq-editing");
+ templating.hideFilename(id);
+ templating.hideEditIcon(id);
+ } else {
+ qqInput.removeClass("qq-editing");
+ templating.showFilename(id);
+ templating.showEditIcon(id);
+ }
+ qqFileContainer.addClass("qq-temp").removeClass("qq-temp");
+ }
+ };
+ },
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ this._parent.prototype._onUploadStatusChange.apply(this, arguments);
+ if (this._isEditFilenameEnabled()) {
+ if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {
+ this._templating.markFilenameEditable(id);
+ this._templating.hideEditIcon(id);
+ }
+ }
+ if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {
+ this._templating.hideRetry(id);
+ this._templating.setStatusText(id);
+ qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);
+ } else if (newStatus === qq.status.UPLOAD_FAILED) {
+ this._templating.hidePause(id);
+ }
+ },
+ _bindFilenameInputFocusInEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameInputFocusInHandler(spec);
+ },
+ _bindFilenameInputFocusEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameInputFocusHandler(spec);
+ },
+ _bindFilenameClickEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameClickHandler(spec);
+ },
+ _storeForLater: function(id) {
+ this._parent.prototype._storeForLater.apply(this, arguments);
+ this._templating.hideSpinner(id);
+ },
+ _onAllComplete: function(successful, failed) {
+ this._parent.prototype._onAllComplete.apply(this, arguments);
+ this._templating.resetTotalProgress();
+ },
+ _onSubmit: function(id, name) {
+ var file = this.getFile(id);
+ if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {
+ this._paramsStore.addReadOnly(id, {
+ qqpath: file.qqPath
+ });
+ }
+ this._parent.prototype._onSubmit.apply(this, arguments);
+ this._addToList(id, name);
+ },
+ _onSubmitted: function(id) {
+ if (this._isEditFilenameEnabled()) {
+ this._templating.markFilenameEditable(id);
+ this._templating.showEditIcon(id);
+ if (!this._focusinEventSupported) {
+ this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));
+ }
+ }
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._parent.prototype._onProgress.apply(this, arguments);
+ this._templating.updateProgress(id, loaded, total);
+ if (total === 0 || Math.round(loaded / total * 100) === 100) {
+ this._templating.hideCancel(id);
+ this._templating.hidePause(id);
+ this._templating.hideProgress(id);
+ this._templating.setStatusText(id, this._options.text.waitingForResponse);
+ this._displayFileSize(id);
+ } else {
+ this._displayFileSize(id, loaded, total);
+ }
+ },
+ _onTotalProgress: function(loaded, total) {
+ this._parent.prototype._onTotalProgress.apply(this, arguments);
+ this._templating.updateTotalProgress(loaded, total);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments), templating = this._templating, fileContainer = templating.getFileContainer(id), self = this;
+ function completeUpload(result) {
+ if (!fileContainer) {
+ return;
+ }
+ templating.setStatusText(id);
+ qq(fileContainer).removeClass(self._classes.retrying);
+ templating.hideProgress(id);
+ if (self.getUploads({
+ id: id
+ }).status !== qq.status.UPLOAD_FAILED) {
+ templating.hideCancel(id);
+ }
+ templating.hideSpinner(id);
+ if (result.success) {
+ self._markFileAsSuccessful(id);
+ } else {
+ qq(fileContainer).addClass(self._classes.fail);
+ templating.showCancel(id);
+ if (templating.isRetryPossible() && !self._preventRetries[id]) {
+ qq(fileContainer).addClass(self._classes.retryable);
+ templating.showRetry(id);
+ }
+ self._controlFailureTextDisplay(id, result);
+ }
+ }
+ if (parentRetVal instanceof qq.Promise) {
+ parentRetVal.done(function(newResult) {
+ completeUpload(newResult);
+ });
+ } else {
+ completeUpload(result);
+ }
+ return parentRetVal;
+ },
+ _markFileAsSuccessful: function(id) {
+ var templating = this._templating;
+ if (this._isDeletePossible()) {
+ templating.showDeleteButton(id);
+ }
+ qq(templating.getFileContainer(id)).addClass(this._classes.success);
+ this._maybeUpdateThumbnail(id);
+ },
+ _onUploadPrep: function(id) {
+ this._parent.prototype._onUploadPrep.apply(this, arguments);
+ this._templating.showSpinner(id);
+ },
+ _onUpload: function(id, name) {
+ var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);
+ this._templating.showSpinner(id);
+ return parentRetVal;
+ },
+ _onUploadChunk: function(id, chunkData) {
+ this._parent.prototype._onUploadChunk.apply(this, arguments);
+ if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {
+ this._templating.allowPause(id);
+ }
+ },
+ _onCancel: function(id, name) {
+ this._parent.prototype._onCancel.apply(this, arguments);
+ this._removeFileItem(id);
+ if (this._getNotFinished() === 0) {
+ this._templating.resetTotalProgress();
+ }
+ },
+ _onBeforeAutoRetry: function(id) {
+ var retryNumForDisplay, maxAuto, retryNote;
+ this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);
+ this._showCancelLink(id);
+ if (this._options.retry.showAutoRetryNote) {
+ retryNumForDisplay = this._autoRetries[id];
+ maxAuto = this._options.retry.maxAutoAttempts;
+ retryNote = this._options.retry.autoRetryNote.replace(/\{retryNum\}/g, retryNumForDisplay);
+ retryNote = retryNote.replace(/\{maxAuto\}/g, maxAuto);
+ this._templating.setStatusText(id, retryNote);
+ qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);
+ }
+ },
+ _onBeforeManualRetry: function(id) {
+ if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {
+ this._templating.resetProgress(id);
+ qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);
+ this._templating.setStatusText(id);
+ this._templating.showSpinner(id);
+ this._showCancelLink(id);
+ return true;
+ } else {
+ qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);
+ this._templating.showRetry(id);
+ return false;
+ }
+ },
+ _onSubmitDelete: function(id) {
+ var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);
+ this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);
+ },
+ _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {
+ if (this._options.deleteFile.forceConfirm) {
+ this._showDeleteConfirm.apply(this, arguments);
+ } else {
+ this._sendDeleteRequest.apply(this, arguments);
+ }
+ },
+ _onDeleteComplete: function(id, xhr, isError) {
+ this._parent.prototype._onDeleteComplete.apply(this, arguments);
+ this._templating.hideSpinner(id);
+ if (isError) {
+ this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);
+ this._templating.showDeleteButton(id);
+ } else {
+ this._removeFileItem(id);
+ }
+ },
+ _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {
+ this._templating.hideDeleteButton(id);
+ this._templating.showSpinner(id);
+ this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);
+ this._deleteHandler.sendDelete.apply(this, arguments);
+ },
+ _showDeleteConfirm: function(id, uuid, mandatedParams) {
+ var fileName = this.getName(id), confirmMessage = this._options.deleteFile.confirmMessage.replace(/\{filename\}/g, fileName), uuid = this.getUuid(id), deleteRequestArgs = arguments, self = this, retVal;
+ retVal = this._options.showConfirm(confirmMessage);
+ if (qq.isGenericPromise(retVal)) {
+ retVal.then(function() {
+ self._sendDeleteRequest.apply(self, deleteRequestArgs);
+ });
+ } else if (retVal !== false) {
+ self._sendDeleteRequest.apply(self, deleteRequestArgs);
+ }
+ },
+ _addToList: function(id, name, canned) {
+ var prependData, prependIndex = 0, dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled, record;
+ if (this._options.display.prependFiles) {
+ if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {
+ prependIndex = this._filesInBatchAddedToUi - 1;
+ }
+ prependData = {
+ index: prependIndex
+ };
+ }
+ if (!canned) {
+ if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {
+ this._templating.disableCancel();
+ }
+ if (!this._options.multiple) {
+ record = this.getUploads({
+ id: id
+ });
+ this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;
+ if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {
+ this._handler.cancelAll();
+ this._clearList();
+ this._handledProxyGroup = null;
+ }
+ }
+ }
+ if (canned) {
+ this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);
+ this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);
+ } else {
+ this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);
+ this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);
+ }
+ this._filesInBatchAddedToUi += 1;
+ if (canned || this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading) {
+ this._displayFileSize(id);
+ }
+ },
+ _clearList: function() {
+ this._templating.clearFiles();
+ this.clearStoredFiles();
+ },
+ _displayFileSize: function(id, loadedSize, totalSize) {
+ var size = this.getSize(id), sizeForDisplay = this._formatSize(size);
+ if (size >= 0) {
+ if (loadedSize !== undefined && totalSize !== undefined) {
+ sizeForDisplay = this._formatProgress(loadedSize, totalSize);
+ }
+ this._templating.updateSize(id, sizeForDisplay);
+ }
+ },
+ _formatProgress: function(uploadedSize, totalSize) {
+ var message = this._options.text.formatProgress;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ r("{percent}", Math.round(uploadedSize / totalSize * 100));
+ r("{total_size}", this._formatSize(totalSize));
+ return message;
+ },
+ _controlFailureTextDisplay: function(id, response) {
+ var mode, responseProperty, failureReason;
+ mode = this._options.failedUploadTextDisplay.mode;
+ responseProperty = this._options.failedUploadTextDisplay.responseProperty;
+ if (mode === "custom") {
+ failureReason = response[responseProperty];
+ if (!failureReason) {
+ failureReason = this._options.text.failUpload;
+ }
+ this._templating.setStatusText(id, failureReason);
+ if (this._options.failedUploadTextDisplay.enableTooltip) {
+ this._showTooltip(id, failureReason);
+ }
+ } else if (mode === "default") {
+ this._templating.setStatusText(id, this._options.text.failUpload);
+ } else if (mode !== "none") {
+ this.log("failedUploadTextDisplay.mode value of '" + mode + "' is not valid", "warn");
+ }
+ },
+ _showTooltip: function(id, text) {
+ this._templating.getFileContainer(id).title = text;
+ },
+ _showCancelLink: function(id) {
+ if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {
+ this._templating.showCancel(id);
+ }
+ },
+ _itemError: function(code, name, item) {
+ var message = this._parent.prototype._itemError.apply(this, arguments);
+ this._options.showMessage(message);
+ },
+ _batchError: function(message) {
+ this._parent.prototype._batchError.apply(this, arguments);
+ this._options.showMessage(message);
+ },
+ _setupPastePrompt: function() {
+ var self = this;
+ this._options.callbacks.onPasteReceived = function() {
+ var message = self._options.paste.namePromptMessage, defaultVal = self._options.paste.defaultName;
+ return self._options.showPrompt(message, defaultVal);
+ };
+ },
+ _fileOrBlobRejected: function(id, name) {
+ this._totalFilesInBatch -= 1;
+ this._parent.prototype._fileOrBlobRejected.apply(this, arguments);
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ this._totalFilesInBatch = items.length;
+ this._filesInBatchAddedToUi = 0;
+ this._parent.prototype._prepareItemsForUpload.apply(this, arguments);
+ },
+ _maybeUpdateThumbnail: function(fileId) {
+ var thumbnailUrl = this._thumbnailUrls[fileId], fileStatus = this.getUploads({
+ id: fileId
+ }).status;
+ if (fileStatus !== qq.status.DELETED && (thumbnailUrl || this._options.thumbnails.placeholders.waitUntilResponse || !qq.supportedFeatures.imagePreviews)) {
+ this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);
+ }
+ },
+ _addCannedFile: function(sessionData) {
+ var id = this._parent.prototype._addCannedFile.apply(this, arguments);
+ this._addToList(id, this.getName(id), true);
+ this._templating.hideSpinner(id);
+ this._templating.hideCancel(id);
+ this._markFileAsSuccessful(id);
+ return id;
+ },
+ _setSize: function(id, newSize) {
+ this._parent.prototype._setSize.apply(this, arguments);
+ this._templating.updateSize(id, this._formatSize(newSize));
+ },
+ _sessionRequestComplete: function() {
+ this._templating.addCacheToDom();
+ this._parent.prototype._sessionRequestComplete.apply(this, arguments);
+ }
+ };
+ })();
+ qq.FineUploader = function(o, namespace) {
+ "use strict";
+ var self = this;
+ this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;
+ this._parent.apply(this, arguments);
+ qq.extend(this._options, {
+ element: null,
+ button: null,
+ listElement: null,
+ dragAndDrop: {
+ extraDropzones: [],
+ reportDirectoryPaths: false
+ },
+ text: {
+ formatProgress: "{percent}% of {total_size}",
+ failUpload: "Upload failed",
+ waitingForResponse: "Processing...",
+ paused: "Paused"
+ },
+ template: "qq-template",
+ classes: {
+ retrying: "qq-upload-retrying",
+ retryable: "qq-upload-retryable",
+ success: "qq-upload-success",
+ fail: "qq-upload-fail",
+ editable: "qq-editable",
+ hide: "qq-hide",
+ dropActive: "qq-upload-drop-area-active"
+ },
+ failedUploadTextDisplay: {
+ mode: "default",
+ responseProperty: "error",
+ enableTooltip: true
+ },
+ messages: {
+ tooManyFilesError: "You may only drop one file",
+ unsupportedBrowser: "Unrecoverable error - this browser does not permit file uploading of any kind."
+ },
+ retry: {
+ showAutoRetryNote: true,
+ autoRetryNote: "Retrying {retryNum}/{maxAuto}..."
+ },
+ deleteFile: {
+ forceConfirm: false,
+ confirmMessage: "Are you sure you want to delete {filename}?",
+ deletingStatusText: "Deleting...",
+ deletingFailedText: "Delete failed"
+ },
+ display: {
+ fileSizeOnSubmit: false,
+ prependFiles: false
+ },
+ paste: {
+ promptForName: false,
+ namePromptMessage: "Please name this image"
+ },
+ thumbnails: {
+ customResizer: null,
+ maxCount: 0,
+ placeholders: {
+ waitUntilResponse: false,
+ notAvailablePath: null,
+ waitingPath: null
+ },
+ timeBetweenThumbs: 750
+ },
+ scaling: {
+ hideScaled: false
+ },
+ showMessage: function(message) {
+ if (self._templating.hasDialog("alert")) {
+ return self._templating.showDialog("alert", message);
+ } else {
+ setTimeout(function() {
+ window.alert(message);
+ }, 0);
+ }
+ },
+ showConfirm: function(message) {
+ if (self._templating.hasDialog("confirm")) {
+ return self._templating.showDialog("confirm", message);
+ } else {
+ return window.confirm(message);
+ }
+ },
+ showPrompt: function(message, defaultValue) {
+ if (self._templating.hasDialog("prompt")) {
+ return self._templating.showDialog("prompt", message, defaultValue);
+ } else {
+ return window.prompt(message, defaultValue);
+ }
+ }
+ }, true);
+ qq.extend(this._options, o, true);
+ this._templating = new qq.Templating({
+ log: qq.bind(this.log, this),
+ templateIdOrEl: this._options.template,
+ containerEl: this._options.element,
+ fileContainerEl: this._options.listElement,
+ button: this._options.button,
+ imageGenerator: this._imageGenerator,
+ classes: {
+ hide: this._options.classes.hide,
+ editable: this._options.classes.editable
+ },
+ limits: {
+ maxThumbs: this._options.thumbnails.maxCount,
+ timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs
+ },
+ placeholders: {
+ waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,
+ thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,
+ waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath
+ },
+ text: this._options.text
+ });
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);
+ } else if (!qq.supportedFeatures.uploading || this._options.cors.expected && !qq.supportedFeatures.uploadCors) {
+ this._templating.renderFailure(this._options.messages.unsupportedBrowser);
+ } else {
+ this._wrapCallbacks();
+ this._templating.render();
+ this._classes = this._options.classes;
+ if (!this._options.button && this._templating.getButton()) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._templating.getButton(),
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._setupClickAndEditEventHandlers();
+ if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {
+ this._dnd = this._setupDragAndDrop();
+ }
+ if (this._options.paste.targetElement && this._options.paste.promptForName) {
+ if (qq.PasteSupport) {
+ this._setupPastePrompt();
+ } else {
+ this.log("Paste support module not found.", "error");
+ }
+ }
+ this._totalFilesInBatch = 0;
+ this._filesInBatchAddedToUi = 0;
+ }
+ };
+ qq.extend(qq.FineUploader.prototype, qq.basePublicApi);
+ qq.extend(qq.FineUploader.prototype, qq.basePrivateApi);
+ qq.extend(qq.FineUploader.prototype, qq.uiPublicApi);
+ qq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);
+ qq.Templating = function(spec) {
+ "use strict";
+ var FILE_ID_ATTR = "qq-file-id", FILE_CLASS_PREFIX = "qq-file-id-", THUMBNAIL_MAX_SIZE_ATTR = "qq-max-size", THUMBNAIL_SERVER_SCALE_ATTR = "qq-server-scale", HIDE_DROPZONE_ATTR = "qq-hide-dropzone", DROPZPONE_TEXT_ATTR = "qq-drop-area-text", IN_PROGRESS_CLASS = "qq-in-progress", HIDDEN_FOREVER_CLASS = "qq-hidden-forever", fileBatch = {
+ content: document.createDocumentFragment(),
+ map: {}
+ }, isCancelDisabled = false, generatedThumbnails = 0, thumbnailQueueMonitorRunning = false, thumbGenerationQueue = [], thumbnailMaxSize = -1, options = {
+ log: null,
+ limits: {
+ maxThumbs: 0,
+ timeBetweenThumbs: 750
+ },
+ templateIdOrEl: "qq-template",
+ containerEl: null,
+ fileContainerEl: null,
+ button: null,
+ imageGenerator: null,
+ classes: {
+ hide: "qq-hide",
+ editable: "qq-editable"
+ },
+ placeholders: {
+ waitUntilUpdate: false,
+ thumbnailNotAvailable: null,
+ waitingForThumbnail: null
+ },
+ text: {
+ paused: "Paused"
+ }
+ }, selectorClasses = {
+ button: "qq-upload-button-selector",
+ alertDialog: "qq-alert-dialog-selector",
+ dialogCancelButton: "qq-cancel-button-selector",
+ confirmDialog: "qq-confirm-dialog-selector",
+ dialogMessage: "qq-dialog-message-selector",
+ dialogOkButton: "qq-ok-button-selector",
+ promptDialog: "qq-prompt-dialog-selector",
+ uploader: "qq-uploader-selector",
+ drop: "qq-upload-drop-area-selector",
+ list: "qq-upload-list-selector",
+ progressBarContainer: "qq-progress-bar-container-selector",
+ progressBar: "qq-progress-bar-selector",
+ totalProgressBarContainer: "qq-total-progress-bar-container-selector",
+ totalProgressBar: "qq-total-progress-bar-selector",
+ file: "qq-upload-file-selector",
+ spinner: "qq-upload-spinner-selector",
+ size: "qq-upload-size-selector",
+ cancel: "qq-upload-cancel-selector",
+ pause: "qq-upload-pause-selector",
+ continueButton: "qq-upload-continue-selector",
+ deleteButton: "qq-upload-delete-selector",
+ retry: "qq-upload-retry-selector",
+ statusText: "qq-upload-status-text-selector",
+ editFilenameInput: "qq-edit-filename-selector",
+ editNameIcon: "qq-edit-filename-icon-selector",
+ dropText: "qq-upload-drop-area-text-selector",
+ dropProcessing: "qq-drop-processing-selector",
+ dropProcessingSpinner: "qq-drop-processing-spinner-selector",
+ thumbnail: "qq-thumbnail-selector"
+ }, previewGeneration = {}, cachedThumbnailNotAvailableImg = new qq.Promise(), cachedWaitingForThumbnailImg = new qq.Promise(), log, isEditElementsExist, isRetryElementExist, templateHtml, container, fileList, showThumbnails, serverScale, cacheThumbnailPlaceholders = function() {
+ var notAvailableUrl = options.placeholders.thumbnailNotAvailable, waitingUrl = options.placeholders.waitingForThumbnail, spec = {
+ maxSize: thumbnailMaxSize,
+ scale: serverScale
+ };
+ if (showThumbnails) {
+ if (notAvailableUrl) {
+ options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(function(updatedImg) {
+ cachedThumbnailNotAvailableImg.success(updatedImg);
+ }, function() {
+ cachedThumbnailNotAvailableImg.failure();
+ log("Problem loading 'not available' placeholder image at " + notAvailableUrl, "error");
+ });
+ } else {
+ cachedThumbnailNotAvailableImg.failure();
+ }
+ if (waitingUrl) {
+ options.imageGenerator.generate(waitingUrl, new Image(), spec).then(function(updatedImg) {
+ cachedWaitingForThumbnailImg.success(updatedImg);
+ }, function() {
+ cachedWaitingForThumbnailImg.failure();
+ log("Problem loading 'waiting for thumbnail' placeholder image at " + waitingUrl, "error");
+ });
+ } else {
+ cachedWaitingForThumbnailImg.failure();
+ }
+ }
+ }, displayWaitingImg = function(thumbnail) {
+ var waitingImgPlacement = new qq.Promise();
+ cachedWaitingForThumbnailImg.then(function(img) {
+ maybeScalePlaceholderViaCss(img, thumbnail);
+ if (!thumbnail.src) {
+ thumbnail.src = img.src;
+ thumbnail.onload = function() {
+ thumbnail.onload = null;
+ show(thumbnail);
+ waitingImgPlacement.success();
+ };
+ } else {
+ waitingImgPlacement.success();
+ }
+ }, function() {
+ hide(thumbnail);
+ waitingImgPlacement.success();
+ });
+ return waitingImgPlacement;
+ }, generateNewPreview = function(id, blob, spec) {
+ var thumbnail = getThumbnail(id);
+ log("Generating new thumbnail for " + id);
+ blob.qqThumbnailId = id;
+ return options.imageGenerator.generate(blob, thumbnail, spec).then(function() {
+ generatedThumbnails++;
+ show(thumbnail);
+ previewGeneration[id].success();
+ }, function() {
+ previewGeneration[id].failure();
+ if (!options.placeholders.waitUntilUpdate) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ }
+ });
+ }, generateNextQueuedPreview = function() {
+ if (thumbGenerationQueue.length) {
+ thumbnailQueueMonitorRunning = true;
+ var queuedThumbRequest = thumbGenerationQueue.shift();
+ if (queuedThumbRequest.update) {
+ processUpdateQueuedPreviewRequest(queuedThumbRequest);
+ } else {
+ processNewQueuedPreviewRequest(queuedThumbRequest);
+ }
+ } else {
+ thumbnailQueueMonitorRunning = false;
+ }
+ }, getCancel = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.cancel);
+ }, getContinue = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.continueButton);
+ }, getDialog = function(type) {
+ return getTemplateEl(container, selectorClasses[type + "Dialog"]);
+ }, getDelete = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.deleteButton);
+ }, getDropProcessing = function() {
+ return getTemplateEl(container, selectorClasses.dropProcessing);
+ }, getEditIcon = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.editNameIcon);
+ }, getFile = function(id) {
+ return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);
+ }, getFilename = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.file);
+ }, getPause = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.pause);
+ }, getProgress = function(id) {
+ if (id == null) {
+ return getTemplateEl(container, selectorClasses.totalProgressBarContainer) || getTemplateEl(container, selectorClasses.totalProgressBar);
+ }
+ return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) || getTemplateEl(getFile(id), selectorClasses.progressBar);
+ }, getRetry = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.retry);
+ }, getSize = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.size);
+ }, getSpinner = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.spinner);
+ }, getTemplateEl = function(context, cssClass) {
+ return context && qq(context).getFirstByClass(cssClass);
+ }, getThumbnail = function(id) {
+ return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);
+ }, hide = function(el) {
+ el && qq(el).addClass(options.classes.hide);
+ }, maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {
+ var maxWidth = placeholder.style.maxWidth, maxHeight = placeholder.style.maxHeight;
+ if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {
+ qq(thumbnail).css({
+ maxWidth: maxWidth,
+ maxHeight: maxHeight
+ });
+ }
+ }, maybeSetDisplayNotAvailableImg = function(id, thumbnail) {
+ var previewing = previewGeneration[id] || new qq.Promise().failure(), notAvailableImgPlacement = new qq.Promise();
+ cachedThumbnailNotAvailableImg.then(function(img) {
+ previewing.then(function() {
+ notAvailableImgPlacement.success();
+ }, function() {
+ maybeScalePlaceholderViaCss(img, thumbnail);
+ thumbnail.onload = function() {
+ thumbnail.onload = null;
+ notAvailableImgPlacement.success();
+ };
+ thumbnail.src = img.src;
+ show(thumbnail);
+ });
+ });
+ return notAvailableImgPlacement;
+ }, parseAndGetTemplate = function() {
+ var scriptEl, scriptHtml, fileListNode, tempTemplateEl, fileListHtml, defaultButton, dropArea, thumbnail, dropProcessing, dropTextEl, uploaderEl;
+ log("Parsing template");
+ if (options.templateIdOrEl == null) {
+ throw new Error("You MUST specify either a template element or ID!");
+ }
+ if (qq.isString(options.templateIdOrEl)) {
+ scriptEl = document.getElementById(options.templateIdOrEl);
+ if (scriptEl === null) {
+ throw new Error(qq.format("Cannot find template script at ID '{}'!", options.templateIdOrEl));
+ }
+ scriptHtml = scriptEl.innerHTML;
+ } else {
+ if (options.templateIdOrEl.innerHTML === undefined) {
+ throw new Error("You have specified an invalid value for the template option! " + "It must be an ID or an Element.");
+ }
+ scriptHtml = options.templateIdOrEl.innerHTML;
+ }
+ scriptHtml = qq.trimStr(scriptHtml);
+ tempTemplateEl = document.createElement("div");
+ tempTemplateEl.appendChild(qq.toElement(scriptHtml));
+ uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);
+ if (options.button) {
+ defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);
+ if (defaultButton) {
+ qq(defaultButton).remove();
+ }
+ }
+ if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {
+ dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);
+ if (dropProcessing) {
+ qq(dropProcessing).remove();
+ }
+ }
+ dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);
+ if (dropArea && !qq.DragAndDrop) {
+ log("DnD module unavailable.", "info");
+ qq(dropArea).remove();
+ }
+ if (!qq.supportedFeatures.fileDrop) {
+ uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);
+ if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {
+ qq(dropArea).css({
+ display: "none"
+ });
+ }
+ } else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {
+ dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);
+ dropTextEl && qq(dropTextEl).remove();
+ }
+ thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);
+ if (!showThumbnails) {
+ thumbnail && qq(thumbnail).remove();
+ } else if (thumbnail) {
+ thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));
+ thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;
+ serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);
+ }
+ showThumbnails = showThumbnails && thumbnail;
+ isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;
+ isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;
+ fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);
+ if (fileListNode == null) {
+ throw new Error("Could not find the file list container in the template!");
+ }
+ fileListHtml = fileListNode.innerHTML;
+ fileListNode.innerHTML = "";
+ if (tempTemplateEl.getElementsByTagName("DIALOG").length) {
+ document.createElement("dialog");
+ }
+ log("Template parsing complete");
+ return {
+ template: qq.trimStr(tempTemplateEl.innerHTML),
+ fileTemplate: qq.trimStr(fileListHtml)
+ };
+ }, prependFile = function(el, index, fileList) {
+ var parentEl = fileList, beforeEl = parentEl.firstChild;
+ if (index > 0) {
+ beforeEl = qq(parentEl).children()[index].nextSibling;
+ }
+ parentEl.insertBefore(el, beforeEl);
+ }, processNewQueuedPreviewRequest = function(queuedThumbRequest) {
+ var id = queuedThumbRequest.id, optFileOrBlob = queuedThumbRequest.optFileOrBlob, relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId, thumbnail = getThumbnail(id), spec = {
+ customResizeFunction: queuedThumbRequest.customResizeFunction,
+ maxSize: thumbnailMaxSize,
+ orient: true,
+ scale: true
+ };
+ if (qq.supportedFeatures.imagePreviews) {
+ if (thumbnail) {
+ if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ } else {
+ displayWaitingImg(thumbnail).done(function() {
+ previewGeneration[id] = new qq.Promise();
+ previewGeneration[id].done(function() {
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ });
+ if (relatedThumbnailId != null) {
+ useCachedPreview(id, relatedThumbnailId);
+ } else {
+ generateNewPreview(id, optFileOrBlob, spec);
+ }
+ });
+ }
+ } else {
+ generateNextQueuedPreview();
+ }
+ } else if (thumbnail) {
+ displayWaitingImg(thumbnail);
+ generateNextQueuedPreview();
+ }
+ }, processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {
+ var id = queuedThumbRequest.id, thumbnailUrl = queuedThumbRequest.thumbnailUrl, showWaitingImg = queuedThumbRequest.showWaitingImg, thumbnail = getThumbnail(id), spec = {
+ customResizeFunction: queuedThumbRequest.customResizeFunction,
+ scale: serverScale,
+ maxSize: thumbnailMaxSize
+ };
+ if (thumbnail) {
+ if (thumbnailUrl) {
+ if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ } else {
+ if (showWaitingImg) {
+ displayWaitingImg(thumbnail);
+ }
+ return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(function() {
+ show(thumbnail);
+ generatedThumbnails++;
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ }, function() {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ });
+ }
+ } else {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ }
+ }
+ }, setProgressBarWidth = function(id, percent) {
+ var bar = getProgress(id), progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;
+ if (bar && !qq(bar).hasClass(progressBarSelector)) {
+ bar = qq(bar).getFirstByClass(progressBarSelector);
+ }
+ if (bar) {
+ qq(bar).css({
+ width: percent + "%"
+ });
+ bar.setAttribute("aria-valuenow", percent);
+ }
+ }, show = function(el) {
+ el && qq(el).removeClass(options.classes.hide);
+ }, useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {
+ var targetThumbnail = getThumbnail(targetThumbnailId), cachedThumbnail = getThumbnail(cachedThumbnailId);
+ log(qq.format("ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));
+ previewGeneration[cachedThumbnailId].then(function() {
+ generatedThumbnails++;
+ previewGeneration[targetThumbnailId].success();
+ log(qq.format("Now using previously generated thumbnail created for ID {} on ID {}.", cachedThumbnailId, targetThumbnailId));
+ targetThumbnail.src = cachedThumbnail.src;
+ show(targetThumbnail);
+ }, function() {
+ previewGeneration[targetThumbnailId].failure();
+ if (!options.placeholders.waitUntilUpdate) {
+ maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);
+ }
+ });
+ };
+ qq.extend(options, spec);
+ log = options.log;
+ if (!qq.supportedFeatures.imagePreviews) {
+ options.limits.timeBetweenThumbs = 0;
+ options.limits.maxThumbs = 0;
+ }
+ container = options.containerEl;
+ showThumbnails = options.imageGenerator !== undefined;
+ templateHtml = parseAndGetTemplate();
+ cacheThumbnailPlaceholders();
+ qq.extend(this, {
+ render: function() {
+ log("Rendering template in DOM.");
+ generatedThumbnails = 0;
+ container.innerHTML = templateHtml.template;
+ hide(getDropProcessing());
+ this.hideTotalProgress();
+ fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);
+ log("Template rendering complete");
+ },
+ renderFailure: function(message) {
+ var cantRenderEl = qq.toElement(message);
+ container.innerHTML = "";
+ container.appendChild(cantRenderEl);
+ },
+ reset: function() {
+ this.render();
+ },
+ clearFiles: function() {
+ fileList.innerHTML = "";
+ },
+ disableCancel: function() {
+ isCancelDisabled = true;
+ },
+ addFile: function(id, name, prependInfo, hideForever, batch) {
+ var fileEl = qq.toElement(templateHtml.fileTemplate), fileNameEl = getTemplateEl(fileEl, selectorClasses.file), uploaderEl = getTemplateEl(container, selectorClasses.uploader), fileContainer = batch ? fileBatch.content : fileList, thumb;
+ if (batch) {
+ fileBatch.map[id] = fileEl;
+ }
+ qq(fileEl).addClass(FILE_CLASS_PREFIX + id);
+ uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);
+ if (fileNameEl) {
+ qq(fileNameEl).setText(name);
+ fileNameEl.setAttribute("title", name);
+ }
+ fileEl.setAttribute(FILE_ID_ATTR, id);
+ if (prependInfo) {
+ prependFile(fileEl, prependInfo.index, fileContainer);
+ } else {
+ fileContainer.appendChild(fileEl);
+ }
+ if (hideForever) {
+ fileEl.style.display = "none";
+ qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);
+ } else {
+ hide(getProgress(id));
+ hide(getSize(id));
+ hide(getDelete(id));
+ hide(getRetry(id));
+ hide(getPause(id));
+ hide(getContinue(id));
+ if (isCancelDisabled) {
+ this.hideCancel(id);
+ }
+ thumb = getThumbnail(id);
+ if (thumb && !thumb.src) {
+ cachedWaitingForThumbnailImg.then(function(waitingImg) {
+ thumb.src = waitingImg.src;
+ if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {
+ qq(thumb).css({
+ maxHeight: waitingImg.style.maxHeight,
+ maxWidth: waitingImg.style.maxWidth
+ });
+ }
+ show(thumb);
+ });
+ }
+ }
+ },
+ addFileToCache: function(id, name, prependInfo, hideForever) {
+ this.addFile(id, name, prependInfo, hideForever, true);
+ },
+ addCacheToDom: function() {
+ fileList.appendChild(fileBatch.content);
+ fileBatch.content = document.createDocumentFragment();
+ fileBatch.map = {};
+ },
+ removeFile: function(id) {
+ qq(getFile(id)).remove();
+ },
+ getFileId: function(el) {
+ var currentNode = el;
+ if (currentNode) {
+ while (currentNode.getAttribute(FILE_ID_ATTR) == null) {
+ currentNode = currentNode.parentNode;
+ }
+ return parseInt(currentNode.getAttribute(FILE_ID_ATTR));
+ }
+ },
+ getFileList: function() {
+ return fileList;
+ },
+ markFilenameEditable: function(id) {
+ var filename = getFilename(id);
+ filename && qq(filename).addClass(options.classes.editable);
+ },
+ updateFilename: function(id, name) {
+ var filenameEl = getFilename(id);
+ if (filenameEl) {
+ qq(filenameEl).setText(name);
+ filenameEl.setAttribute("title", name);
+ }
+ },
+ hideFilename: function(id) {
+ hide(getFilename(id));
+ },
+ showFilename: function(id) {
+ show(getFilename(id));
+ },
+ isFileName: function(el) {
+ return qq(el).hasClass(selectorClasses.file);
+ },
+ getButton: function() {
+ return options.button || getTemplateEl(container, selectorClasses.button);
+ },
+ hideDropProcessing: function() {
+ hide(getDropProcessing());
+ },
+ showDropProcessing: function() {
+ show(getDropProcessing());
+ },
+ getDropZone: function() {
+ return getTemplateEl(container, selectorClasses.drop);
+ },
+ isEditFilenamePossible: function() {
+ return isEditElementsExist;
+ },
+ hideRetry: function(id) {
+ hide(getRetry(id));
+ },
+ isRetryPossible: function() {
+ return isRetryElementExist;
+ },
+ showRetry: function(id) {
+ show(getRetry(id));
+ },
+ getFileContainer: function(id) {
+ return getFile(id);
+ },
+ showEditIcon: function(id) {
+ var icon = getEditIcon(id);
+ icon && qq(icon).addClass(options.classes.editable);
+ },
+ isHiddenForever: function(id) {
+ return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);
+ },
+ hideEditIcon: function(id) {
+ var icon = getEditIcon(id);
+ icon && qq(icon).removeClass(options.classes.editable);
+ },
+ isEditIcon: function(el) {
+ return qq(el).hasClass(selectorClasses.editNameIcon, true);
+ },
+ getEditInput: function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);
+ },
+ isEditInput: function(el) {
+ return qq(el).hasClass(selectorClasses.editFilenameInput, true);
+ },
+ updateProgress: function(id, loaded, total) {
+ var bar = getProgress(id), percent;
+ if (bar && total > 0) {
+ percent = Math.round(loaded / total * 100);
+ if (percent === 100) {
+ hide(bar);
+ } else {
+ show(bar);
+ }
+ setProgressBarWidth(id, percent);
+ }
+ },
+ updateTotalProgress: function(loaded, total) {
+ this.updateProgress(null, loaded, total);
+ },
+ hideProgress: function(id) {
+ var bar = getProgress(id);
+ bar && hide(bar);
+ },
+ hideTotalProgress: function() {
+ this.hideProgress();
+ },
+ resetProgress: function(id) {
+ setProgressBarWidth(id, 0);
+ this.hideTotalProgress(id);
+ },
+ resetTotalProgress: function() {
+ this.resetProgress();
+ },
+ showCancel: function(id) {
+ if (!isCancelDisabled) {
+ var cancel = getCancel(id);
+ cancel && qq(cancel).removeClass(options.classes.hide);
+ }
+ },
+ hideCancel: function(id) {
+ hide(getCancel(id));
+ },
+ isCancel: function(el) {
+ return qq(el).hasClass(selectorClasses.cancel, true);
+ },
+ allowPause: function(id) {
+ show(getPause(id));
+ hide(getContinue(id));
+ },
+ uploadPaused: function(id) {
+ this.setStatusText(id, options.text.paused);
+ this.allowContinueButton(id);
+ hide(getSpinner(id));
+ },
+ hidePause: function(id) {
+ hide(getPause(id));
+ },
+ isPause: function(el) {
+ return qq(el).hasClass(selectorClasses.pause, true);
+ },
+ isContinueButton: function(el) {
+ return qq(el).hasClass(selectorClasses.continueButton, true);
+ },
+ allowContinueButton: function(id) {
+ show(getContinue(id));
+ hide(getPause(id));
+ },
+ uploadContinued: function(id) {
+ this.setStatusText(id, "");
+ this.allowPause(id);
+ show(getSpinner(id));
+ },
+ showDeleteButton: function(id) {
+ show(getDelete(id));
+ },
+ hideDeleteButton: function(id) {
+ hide(getDelete(id));
+ },
+ isDeleteButton: function(el) {
+ return qq(el).hasClass(selectorClasses.deleteButton, true);
+ },
+ isRetry: function(el) {
+ return qq(el).hasClass(selectorClasses.retry, true);
+ },
+ updateSize: function(id, text) {
+ var size = getSize(id);
+ if (size) {
+ show(size);
+ qq(size).setText(text);
+ }
+ },
+ setStatusText: function(id, text) {
+ var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);
+ if (textEl) {
+ if (text == null) {
+ qq(textEl).clearText();
+ } else {
+ qq(textEl).setText(text);
+ }
+ }
+ },
+ hideSpinner: function(id) {
+ qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);
+ hide(getSpinner(id));
+ },
+ showSpinner: function(id) {
+ qq(getFile(id)).addClass(IN_PROGRESS_CLASS);
+ show(getSpinner(id));
+ },
+ generatePreview: function(id, optFileOrBlob, customResizeFunction) {
+ if (!this.isHiddenForever(id)) {
+ thumbGenerationQueue.push({
+ id: id,
+ customResizeFunction: customResizeFunction,
+ optFileOrBlob: optFileOrBlob
+ });
+ !thumbnailQueueMonitorRunning && generateNextQueuedPreview();
+ }
+ },
+ updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {
+ if (!this.isHiddenForever(id)) {
+ thumbGenerationQueue.push({
+ customResizeFunction: customResizeFunction,
+ update: true,
+ id: id,
+ thumbnailUrl: thumbnailUrl,
+ showWaitingImg: showWaitingImg
+ });
+ !thumbnailQueueMonitorRunning && generateNextQueuedPreview();
+ }
+ },
+ hasDialog: function(type) {
+ return qq.supportedFeatures.dialogElement && !!getDialog(type);
+ },
+ showDialog: function(type, message, defaultValue) {
+ var dialog = getDialog(type), messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage), inputEl = dialog.getElementsByTagName("INPUT")[0], cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton), okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton), promise = new qq.Promise(), closeHandler = function() {
+ cancelBtn.removeEventListener("click", cancelClickHandler);
+ okBtn && okBtn.removeEventListener("click", okClickHandler);
+ promise.failure();
+ }, cancelClickHandler = function() {
+ cancelBtn.removeEventListener("click", cancelClickHandler);
+ dialog.close();
+ }, okClickHandler = function() {
+ dialog.removeEventListener("close", closeHandler);
+ okBtn.removeEventListener("click", okClickHandler);
+ dialog.close();
+ promise.success(inputEl && inputEl.value);
+ };
+ dialog.addEventListener("close", closeHandler);
+ cancelBtn.addEventListener("click", cancelClickHandler);
+ okBtn && okBtn.addEventListener("click", okClickHandler);
+ if (inputEl) {
+ inputEl.value = defaultValue;
+ }
+ messageEl.textContent = message;
+ dialog.showModal();
+ return promise;
+ }
+ });
+ };
+ qq.UiEventHandler = function(s, protectedApi) {
+ "use strict";
+ var disposer = new qq.DisposeSupport(), spec = {
+ eventType: "click",
+ attachTo: null,
+ onHandled: function(target, event) {}
+ };
+ qq.extend(this, {
+ addHandler: function(element) {
+ addHandler(element);
+ },
+ dispose: function() {
+ disposer.dispose();
+ }
+ });
+ function addHandler(element) {
+ disposer.attach(element, spec.eventType, function(event) {
+ event = event || window.event;
+ var target = event.target || event.srcElement;
+ spec.onHandled(target, event);
+ });
+ }
+ qq.extend(protectedApi, {
+ getFileIdFromItem: function(item) {
+ return item.qqFileId;
+ },
+ getDisposeSupport: function() {
+ return disposer;
+ }
+ });
+ qq.extend(spec, s);
+ if (spec.attachTo) {
+ addHandler(spec.attachTo);
+ }
+ };
+ qq.FileButtonsClickHandler = function(s) {
+ "use strict";
+ var inheritedInternalApi = {}, spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ onDeleteFile: function(fileId) {},
+ onCancel: function(fileId) {},
+ onRetry: function(fileId) {},
+ onPause: function(fileId) {},
+ onContinue: function(fileId) {},
+ onGetName: function(fileId) {}
+ }, buttonHandlers = {
+ cancel: function(id) {
+ spec.onCancel(id);
+ },
+ retry: function(id) {
+ spec.onRetry(id);
+ },
+ deleteButton: function(id) {
+ spec.onDeleteFile(id);
+ },
+ pause: function(id) {
+ spec.onPause(id);
+ },
+ continueButton: function(id) {
+ spec.onContinue(id);
+ }
+ };
+ function examineEvent(target, event) {
+ qq.each(buttonHandlers, function(buttonType, handler) {
+ var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1), fileId;
+ if (spec.templating["is" + firstLetterCapButtonType](target)) {
+ fileId = spec.templating.getFileId(target);
+ qq.preventDefault(event);
+ spec.log(qq.format("Detected valid file button click event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ handler(fileId);
+ return false;
+ }
+ });
+ }
+ qq.extend(spec, s);
+ spec.eventType = "click";
+ spec.onHandled = examineEvent;
+ spec.attachTo = spec.templating.getFileList();
+ qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameClickHandler = function(s) {
+ "use strict";
+ var inheritedInternalApi = {}, spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ classes: {
+ file: "qq-upload-file",
+ editNameIcon: "qq-edit-filename-icon"
+ },
+ onGetUploadStatus: function(fileId) {},
+ onGetName: function(fileId) {}
+ };
+ qq.extend(spec, s);
+ function examineEvent(target, event) {
+ if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {
+ var fileId = spec.templating.getFileId(target), status = spec.onGetUploadStatus(fileId);
+ if (status === qq.status.SUBMITTED) {
+ spec.log(qq.format("Detected valid filename click event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ qq.preventDefault(event);
+ inheritedInternalApi.handleFilenameEdit(fileId, target, true);
+ }
+ }
+ }
+ spec.eventType = "click";
+ spec.onHandled = examineEvent;
+ qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {
+ "use strict";
+ var spec = {
+ templating: null,
+ onGetUploadStatus: function(fileId) {},
+ log: function(message, lvl) {}
+ };
+ if (!inheritedInternalApi) {
+ inheritedInternalApi = {};
+ }
+ function handleInputFocus(target, event) {
+ if (spec.templating.isEditInput(target)) {
+ var fileId = spec.templating.getFileId(target), status = spec.onGetUploadStatus(fileId);
+ if (status === qq.status.SUBMITTED) {
+ spec.log(qq.format("Detected valid filename input focus event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ inheritedInternalApi.handleFilenameEdit(fileId, target);
+ }
+ }
+ }
+ spec.eventType = "focusin";
+ spec.onHandled = handleInputFocus;
+ qq.extend(spec, s);
+ qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameInputFocusHandler = function(spec) {
+ "use strict";
+ spec.eventType = "focus";
+ spec.attachTo = null;
+ qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));
+ };
+ qq.FilenameEditHandler = function(s, inheritedInternalApi) {
+ "use strict";
+ var spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ onGetUploadStatus: function(fileId) {},
+ onGetName: function(fileId) {},
+ onSetName: function(fileId, newName) {},
+ onEditingStatusChange: function(fileId, isEditing) {}
+ };
+ function getFilenameSansExtension(fileId) {
+ var filenameSansExt = spec.onGetName(fileId), extIdx = filenameSansExt.lastIndexOf(".");
+ if (extIdx > 0) {
+ filenameSansExt = filenameSansExt.substr(0, extIdx);
+ }
+ return filenameSansExt;
+ }
+ function getOriginalExtension(fileId) {
+ var origName = spec.onGetName(fileId);
+ return qq.getExtension(origName);
+ }
+ function handleNameUpdate(newFilenameInputEl, fileId) {
+ var newName = newFilenameInputEl.value, origExtension;
+ if (newName !== undefined && qq.trimStr(newName).length > 0) {
+ origExtension = getOriginalExtension(fileId);
+ if (origExtension !== undefined) {
+ newName = newName + "." + origExtension;
+ }
+ spec.onSetName(fileId, newName);
+ }
+ spec.onEditingStatusChange(fileId, false);
+ }
+ function registerInputBlurHandler(inputEl, fileId) {
+ inheritedInternalApi.getDisposeSupport().attach(inputEl, "blur", function() {
+ handleNameUpdate(inputEl, fileId);
+ });
+ }
+ function registerInputEnterKeyHandler(inputEl, fileId) {
+ inheritedInternalApi.getDisposeSupport().attach(inputEl, "keyup", function(event) {
+ var code = event.keyCode || event.which;
+ if (code === 13) {
+ handleNameUpdate(inputEl, fileId);
+ }
+ });
+ }
+ qq.extend(spec, s);
+ spec.attachTo = spec.templating.getFileList();
+ qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));
+ qq.extend(inheritedInternalApi, {
+ handleFilenameEdit: function(id, target, focusInput) {
+ var newFilenameInputEl = spec.templating.getEditInput(id);
+ spec.onEditingStatusChange(id, true);
+ newFilenameInputEl.value = getFilenameSansExtension(id);
+ if (focusInput) {
+ newFilenameInputEl.focus();
+ }
+ registerInputBlurHandler(newFilenameInputEl, id);
+ registerInputEnterKeyHandler(newFilenameInputEl, id);
+ }
+ });
+ };
+ qq.CryptoJS = function(Math, undefined) {
+ var C = {};
+ var C_lib = C.lib = {};
+ var Base = C_lib.Base = function() {
+ function F() {}
+ return {
+ extend: function(overrides) {
+ F.prototype = this;
+ var subtype = new F();
+ if (overrides) {
+ subtype.mixIn(overrides);
+ }
+ if (!subtype.hasOwnProperty("init")) {
+ subtype.init = function() {
+ subtype.$super.init.apply(this, arguments);
+ };
+ }
+ subtype.init.prototype = subtype;
+ subtype.$super = this;
+ return subtype;
+ },
+ create: function() {
+ var instance = this.extend();
+ instance.init.apply(instance, arguments);
+ return instance;
+ },
+ init: function() {},
+ mixIn: function(properties) {
+ for (var propertyName in properties) {
+ if (properties.hasOwnProperty(propertyName)) {
+ this[propertyName] = properties[propertyName];
+ }
+ }
+ if (properties.hasOwnProperty("toString")) {
+ this.toString = properties.toString;
+ }
+ },
+ clone: function() {
+ return this.init.prototype.extend(this);
+ }
+ };
+ }();
+ var WordArray = C_lib.WordArray = Base.extend({
+ init: function(words, sigBytes) {
+ words = this.words = words || [];
+ if (sigBytes != undefined) {
+ this.sigBytes = sigBytes;
+ } else {
+ this.sigBytes = words.length * 4;
+ }
+ },
+ toString: function(encoder) {
+ return (encoder || Hex).stringify(this);
+ },
+ concat: function(wordArray) {
+ var thisWords = this.words;
+ var thatWords = wordArray.words;
+ var thisSigBytes = this.sigBytes;
+ var thatSigBytes = wordArray.sigBytes;
+ this.clamp();
+ if (thisSigBytes % 4) {
+ for (var i = 0; i < thatSigBytes; i++) {
+ var thatByte = thatWords[i >>> 2] >>> 24 - i % 4 * 8 & 255;
+ thisWords[thisSigBytes + i >>> 2] |= thatByte << 24 - (thisSigBytes + i) % 4 * 8;
+ }
+ } else if (thatWords.length > 65535) {
+ for (var i = 0; i < thatSigBytes; i += 4) {
+ thisWords[thisSigBytes + i >>> 2] = thatWords[i >>> 2];
+ }
+ } else {
+ thisWords.push.apply(thisWords, thatWords);
+ }
+ this.sigBytes += thatSigBytes;
+ return this;
+ },
+ clamp: function() {
+ var words = this.words;
+ var sigBytes = this.sigBytes;
+ words[sigBytes >>> 2] &= 4294967295 << 32 - sigBytes % 4 * 8;
+ words.length = Math.ceil(sigBytes / 4);
+ },
+ clone: function() {
+ var clone = Base.clone.call(this);
+ clone.words = this.words.slice(0);
+ return clone;
+ },
+ random: function(nBytes) {
+ var words = [];
+ for (var i = 0; i < nBytes; i += 4) {
+ words.push(Math.random() * 4294967296 | 0);
+ }
+ return new WordArray.init(words, nBytes);
+ }
+ });
+ var C_enc = C.enc = {};
+ var Hex = C_enc.Hex = {
+ stringify: function(wordArray) {
+ var words = wordArray.words;
+ var sigBytes = wordArray.sigBytes;
+ var hexChars = [];
+ for (var i = 0; i < sigBytes; i++) {
+ var bite = words[i >>> 2] >>> 24 - i % 4 * 8 & 255;
+ hexChars.push((bite >>> 4).toString(16));
+ hexChars.push((bite & 15).toString(16));
+ }
+ return hexChars.join("");
+ },
+ parse: function(hexStr) {
+ var hexStrLength = hexStr.length;
+ var words = [];
+ for (var i = 0; i < hexStrLength; i += 2) {
+ words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << 24 - i % 8 * 4;
+ }
+ return new WordArray.init(words, hexStrLength / 2);
+ }
+ };
+ var Latin1 = C_enc.Latin1 = {
+ stringify: function(wordArray) {
+ var words = wordArray.words;
+ var sigBytes = wordArray.sigBytes;
+ var latin1Chars = [];
+ for (var i = 0; i < sigBytes; i++) {
+ var bite = words[i >>> 2] >>> 24 - i % 4 * 8 & 255;
+ latin1Chars.push(String.fromCharCode(bite));
+ }
+ return latin1Chars.join("");
+ },
+ parse: function(latin1Str) {
+ var latin1StrLength = latin1Str.length;
+ var words = [];
+ for (var i = 0; i < latin1StrLength; i++) {
+ words[i >>> 2] |= (latin1Str.charCodeAt(i) & 255) << 24 - i % 4 * 8;
+ }
+ return new WordArray.init(words, latin1StrLength);
+ }
+ };
+ var Utf8 = C_enc.Utf8 = {
+ stringify: function(wordArray) {
+ try {
+ return decodeURIComponent(escape(Latin1.stringify(wordArray)));
+ } catch (e) {
+ throw new Error("Malformed UTF-8 data");
+ }
+ },
+ parse: function(utf8Str) {
+ return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
+ }
+ };
+ var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
+ reset: function() {
+ this._data = new WordArray.init();
+ this._nDataBytes = 0;
+ },
+ _append: function(data) {
+ if (typeof data == "string") {
+ data = Utf8.parse(data);
+ }
+ this._data.concat(data);
+ this._nDataBytes += data.sigBytes;
+ },
+ _process: function(doFlush) {
+ var data = this._data;
+ var dataWords = data.words;
+ var dataSigBytes = data.sigBytes;
+ var blockSize = this.blockSize;
+ var blockSizeBytes = blockSize * 4;
+ var nBlocksReady = dataSigBytes / blockSizeBytes;
+ if (doFlush) {
+ nBlocksReady = Math.ceil(nBlocksReady);
+ } else {
+ nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
+ }
+ var nWordsReady = nBlocksReady * blockSize;
+ var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
+ if (nWordsReady) {
+ for (var offset = 0; offset < nWordsReady; offset += blockSize) {
+ this._doProcessBlock(dataWords, offset);
+ }
+ var processedWords = dataWords.splice(0, nWordsReady);
+ data.sigBytes -= nBytesReady;
+ }
+ return new WordArray.init(processedWords, nBytesReady);
+ },
+ clone: function() {
+ var clone = Base.clone.call(this);
+ clone._data = this._data.clone();
+ return clone;
+ },
+ _minBufferSize: 0
+ });
+ var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
+ cfg: Base.extend(),
+ init: function(cfg) {
+ this.cfg = this.cfg.extend(cfg);
+ this.reset();
+ },
+ reset: function() {
+ BufferedBlockAlgorithm.reset.call(this);
+ this._doReset();
+ },
+ update: function(messageUpdate) {
+ this._append(messageUpdate);
+ this._process();
+ return this;
+ },
+ finalize: function(messageUpdate) {
+ if (messageUpdate) {
+ this._append(messageUpdate);
+ }
+ var hash = this._doFinalize();
+ return hash;
+ },
+ blockSize: 512 / 32,
+ _createHelper: function(hasher) {
+ return function(message, cfg) {
+ return new hasher.init(cfg).finalize(message);
+ };
+ },
+ _createHmacHelper: function(hasher) {
+ return function(message, key) {
+ return new C_algo.HMAC.init(hasher, key).finalize(message);
+ };
+ }
+ });
+ var C_algo = C.algo = {};
+ return C;
+ }(Math);
+ (function() {
+ var C = qq.CryptoJS;
+ var C_lib = C.lib;
+ var WordArray = C_lib.WordArray;
+ var C_enc = C.enc;
+ var Base64 = C_enc.Base64 = {
+ stringify: function(wordArray) {
+ var words = wordArray.words;
+ var sigBytes = wordArray.sigBytes;
+ var map = this._map;
+ wordArray.clamp();
+ var base64Chars = [];
+ for (var i = 0; i < sigBytes; i += 3) {
+ var byte1 = words[i >>> 2] >>> 24 - i % 4 * 8 & 255;
+ var byte2 = words[i + 1 >>> 2] >>> 24 - (i + 1) % 4 * 8 & 255;
+ var byte3 = words[i + 2 >>> 2] >>> 24 - (i + 2) % 4 * 8 & 255;
+ var triplet = byte1 << 16 | byte2 << 8 | byte3;
+ for (var j = 0; j < 4 && i + j * .75 < sigBytes; j++) {
+ base64Chars.push(map.charAt(triplet >>> 6 * (3 - j) & 63));
+ }
+ }
+ var paddingChar = map.charAt(64);
+ if (paddingChar) {
+ while (base64Chars.length % 4) {
+ base64Chars.push(paddingChar);
+ }
+ }
+ return base64Chars.join("");
+ },
+ parse: function(base64Str) {
+ var base64StrLength = base64Str.length;
+ var map = this._map;
+ var paddingChar = map.charAt(64);
+ if (paddingChar) {
+ var paddingIndex = base64Str.indexOf(paddingChar);
+ if (paddingIndex != -1) {
+ base64StrLength = paddingIndex;
+ }
+ }
+ var words = [];
+ var nBytes = 0;
+ for (var i = 0; i < base64StrLength; i++) {
+ if (i % 4) {
+ var bits1 = map.indexOf(base64Str.charAt(i - 1)) << i % 4 * 2;
+ var bits2 = map.indexOf(base64Str.charAt(i)) >>> 6 - i % 4 * 2;
+ words[nBytes >>> 2] |= (bits1 | bits2) << 24 - nBytes % 4 * 8;
+ nBytes++;
+ }
+ }
+ return WordArray.create(words, nBytes);
+ },
+ _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
+ };
+ })();
+ (function() {
+ var C = qq.CryptoJS;
+ var C_lib = C.lib;
+ var Base = C_lib.Base;
+ var C_enc = C.enc;
+ var Utf8 = C_enc.Utf8;
+ var C_algo = C.algo;
+ var HMAC = C_algo.HMAC = Base.extend({
+ init: function(hasher, key) {
+ hasher = this._hasher = new hasher.init();
+ if (typeof key == "string") {
+ key = Utf8.parse(key);
+ }
+ var hasherBlockSize = hasher.blockSize;
+ var hasherBlockSizeBytes = hasherBlockSize * 4;
+ if (key.sigBytes > hasherBlockSizeBytes) {
+ key = hasher.finalize(key);
+ }
+ key.clamp();
+ var oKey = this._oKey = key.clone();
+ var iKey = this._iKey = key.clone();
+ var oKeyWords = oKey.words;
+ var iKeyWords = iKey.words;
+ for (var i = 0; i < hasherBlockSize; i++) {
+ oKeyWords[i] ^= 1549556828;
+ iKeyWords[i] ^= 909522486;
+ }
+ oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;
+ this.reset();
+ },
+ reset: function() {
+ var hasher = this._hasher;
+ hasher.reset();
+ hasher.update(this._iKey);
+ },
+ update: function(messageUpdate) {
+ this._hasher.update(messageUpdate);
+ return this;
+ },
+ finalize: function(messageUpdate) {
+ var hasher = this._hasher;
+ var innerHash = hasher.finalize(messageUpdate);
+ hasher.reset();
+ var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));
+ return hmac;
+ }
+ });
+ })();
+ (function() {
+ var C = qq.CryptoJS;
+ var C_lib = C.lib;
+ var WordArray = C_lib.WordArray;
+ var Hasher = C_lib.Hasher;
+ var C_algo = C.algo;
+ var W = [];
+ var SHA1 = C_algo.SHA1 = Hasher.extend({
+ _doReset: function() {
+ this._hash = new WordArray.init([ 1732584193, 4023233417, 2562383102, 271733878, 3285377520 ]);
+ },
+ _doProcessBlock: function(M, offset) {
+ var H = this._hash.words;
+ var a = H[0];
+ var b = H[1];
+ var c = H[2];
+ var d = H[3];
+ var e = H[4];
+ for (var i = 0; i < 80; i++) {
+ if (i < 16) {
+ W[i] = M[offset + i] | 0;
+ } else {
+ var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
+ W[i] = n << 1 | n >>> 31;
+ }
+ var t = (a << 5 | a >>> 27) + e + W[i];
+ if (i < 20) {
+ t += (b & c | ~b & d) + 1518500249;
+ } else if (i < 40) {
+ t += (b ^ c ^ d) + 1859775393;
+ } else if (i < 60) {
+ t += (b & c | b & d | c & d) - 1894007588;
+ } else {
+ t += (b ^ c ^ d) - 899497514;
+ }
+ e = d;
+ d = c;
+ c = b << 30 | b >>> 2;
+ b = a;
+ a = t;
+ }
+ H[0] = H[0] + a | 0;
+ H[1] = H[1] + b | 0;
+ H[2] = H[2] + c | 0;
+ H[3] = H[3] + d | 0;
+ H[4] = H[4] + e | 0;
+ },
+ _doFinalize: function() {
+ var data = this._data;
+ var dataWords = data.words;
+ var nBitsTotal = this._nDataBytes * 8;
+ var nBitsLeft = data.sigBytes * 8;
+ dataWords[nBitsLeft >>> 5] |= 128 << 24 - nBitsLeft % 32;
+ dataWords[(nBitsLeft + 64 >>> 9 << 4) + 14] = Math.floor(nBitsTotal / 4294967296);
+ dataWords[(nBitsLeft + 64 >>> 9 << 4) + 15] = nBitsTotal;
+ data.sigBytes = dataWords.length * 4;
+ this._process();
+ return this._hash;
+ },
+ clone: function() {
+ var clone = Hasher.clone.call(this);
+ clone._hash = this._hash.clone();
+ return clone;
+ }
+ });
+ C.SHA1 = Hasher._createHelper(SHA1);
+ C.HmacSHA1 = Hasher._createHmacHelper(SHA1);
+ })();
+ (function(Math) {
+ var C = qq.CryptoJS;
+ var C_lib = C.lib;
+ var WordArray = C_lib.WordArray;
+ var Hasher = C_lib.Hasher;
+ var C_algo = C.algo;
+ var H = [];
+ var K = [];
+ (function() {
+ function isPrime(n) {
+ var sqrtN = Math.sqrt(n);
+ for (var factor = 2; factor <= sqrtN; factor++) {
+ if (!(n % factor)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ function getFractionalBits(n) {
+ return (n - (n | 0)) * 4294967296 | 0;
+ }
+ var n = 2;
+ var nPrime = 0;
+ while (nPrime < 64) {
+ if (isPrime(n)) {
+ if (nPrime < 8) {
+ H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));
+ }
+ K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));
+ nPrime++;
+ }
+ n++;
+ }
+ })();
+ var W = [];
+ var SHA256 = C_algo.SHA256 = Hasher.extend({
+ _doReset: function() {
+ this._hash = new WordArray.init(H.slice(0));
+ },
+ _doProcessBlock: function(M, offset) {
+ var H = this._hash.words;
+ var a = H[0];
+ var b = H[1];
+ var c = H[2];
+ var d = H[3];
+ var e = H[4];
+ var f = H[5];
+ var g = H[6];
+ var h = H[7];
+ for (var i = 0; i < 64; i++) {
+ if (i < 16) {
+ W[i] = M[offset + i] | 0;
+ } else {
+ var gamma0x = W[i - 15];
+ var gamma0 = (gamma0x << 25 | gamma0x >>> 7) ^ (gamma0x << 14 | gamma0x >>> 18) ^ gamma0x >>> 3;
+ var gamma1x = W[i - 2];
+ var gamma1 = (gamma1x << 15 | gamma1x >>> 17) ^ (gamma1x << 13 | gamma1x >>> 19) ^ gamma1x >>> 10;
+ W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
+ }
+ var ch = e & f ^ ~e & g;
+ var maj = a & b ^ a & c ^ b & c;
+ var sigma0 = (a << 30 | a >>> 2) ^ (a << 19 | a >>> 13) ^ (a << 10 | a >>> 22);
+ var sigma1 = (e << 26 | e >>> 6) ^ (e << 21 | e >>> 11) ^ (e << 7 | e >>> 25);
+ var t1 = h + sigma1 + ch + K[i] + W[i];
+ var t2 = sigma0 + maj;
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1 | 0;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2 | 0;
+ }
+ H[0] = H[0] + a | 0;
+ H[1] = H[1] + b | 0;
+ H[2] = H[2] + c | 0;
+ H[3] = H[3] + d | 0;
+ H[4] = H[4] + e | 0;
+ H[5] = H[5] + f | 0;
+ H[6] = H[6] + g | 0;
+ H[7] = H[7] + h | 0;
+ },
+ _doFinalize: function() {
+ var data = this._data;
+ var dataWords = data.words;
+ var nBitsTotal = this._nDataBytes * 8;
+ var nBitsLeft = data.sigBytes * 8;
+ dataWords[nBitsLeft >>> 5] |= 128 << 24 - nBitsLeft % 32;
+ dataWords[(nBitsLeft + 64 >>> 9 << 4) + 14] = Math.floor(nBitsTotal / 4294967296);
+ dataWords[(nBitsLeft + 64 >>> 9 << 4) + 15] = nBitsTotal;
+ data.sigBytes = dataWords.length * 4;
+ this._process();
+ return this._hash;
+ },
+ clone: function() {
+ var clone = Hasher.clone.call(this);
+ clone._hash = this._hash.clone();
+ return clone;
+ }
+ });
+ C.SHA256 = Hasher._createHelper(SHA256);
+ C.HmacSHA256 = Hasher._createHmacHelper(SHA256);
+ })(Math);
+ (function() {
+ if (typeof ArrayBuffer != "function") {
+ return;
+ }
+ var C = qq.CryptoJS;
+ var C_lib = C.lib;
+ var WordArray = C_lib.WordArray;
+ var superInit = WordArray.init;
+ var subInit = WordArray.init = function(typedArray) {
+ if (typedArray instanceof ArrayBuffer) {
+ typedArray = new Uint8Array(typedArray);
+ }
+ if (typedArray instanceof Int8Array || typedArray instanceof Uint8ClampedArray || typedArray instanceof Int16Array || typedArray instanceof Uint16Array || typedArray instanceof Int32Array || typedArray instanceof Uint32Array || typedArray instanceof Float32Array || typedArray instanceof Float64Array) {
+ typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);
+ }
+ if (typedArray instanceof Uint8Array) {
+ var typedArrayByteLength = typedArray.byteLength;
+ var words = [];
+ for (var i = 0; i < typedArrayByteLength; i++) {
+ words[i >>> 2] |= typedArray[i] << 24 - i % 4 * 8;
+ }
+ superInit.call(this, words, typedArrayByteLength);
+ } else {
+ superInit.apply(this, arguments);
+ }
+ };
+ subInit.prototype = WordArray;
+ })();
+ qq.s3 = qq.s3 || {};
+ qq.s3.util = qq.s3.util || function() {
+ "use strict";
+ return {
+ ALGORITHM_PARAM_NAME: "x-amz-algorithm",
+ AWS_PARAM_PREFIX: "x-amz-meta-",
+ CREDENTIAL_PARAM_NAME: "x-amz-credential",
+ DATE_PARAM_NAME: "x-amz-date",
+ REDUCED_REDUNDANCY_PARAM_NAME: "x-amz-storage-class",
+ REDUCED_REDUNDANCY_PARAM_VALUE: "REDUCED_REDUNDANCY",
+ SERVER_SIDE_ENCRYPTION_PARAM_NAME: "x-amz-server-side-encryption",
+ SERVER_SIDE_ENCRYPTION_PARAM_VALUE: "AES256",
+ SESSION_TOKEN_PARAM_NAME: "x-amz-security-token",
+ V4_ALGORITHM_PARAM_VALUE: "AWS4-HMAC-SHA256",
+ V4_SIGNATURE_PARAM_NAME: "x-amz-signature",
+ CASE_SENSITIVE_PARAM_NAMES: [ "Cache-Control", "Content-Disposition", "Content-Encoding", "Content-MD5" ],
+ UNSIGNABLE_REST_HEADER_NAMES: [ "Cache-Control", "Content-Disposition", "Content-Encoding", "Content-MD5" ],
+ UNPREFIXED_PARAM_NAMES: [ "Cache-Control", "Content-Disposition", "Content-Encoding", "Content-MD5", "x-amz-server-side-encryption-customer-algorithm", "x-amz-server-side-encryption-customer-key", "x-amz-server-side-encryption-customer-key-MD5" ],
+ getBucket: function(endpoint) {
+ var patterns = [ /^(?:https?:\/\/)?([a-z0-9.\-_]+)\.s3(?:-[a-z0-9\-]+)?\.amazonaws\.com/i, /^(?:https?:\/\/)?s3(?:-[a-z0-9\-]+)?\.amazonaws\.com\/([a-z0-9.\-_]+)/i, /^(?:https?:\/\/)?([a-z0-9.\-_]+)/i ], bucket;
+ qq.each(patterns, function(idx, pattern) {
+ var match = pattern.exec(endpoint);
+ if (match) {
+ bucket = match[1];
+ return false;
+ }
+ });
+ return bucket;
+ },
+ _getPrefixedParamName: function(name) {
+ if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {
+ return name;
+ }
+ return qq.s3.util.AWS_PARAM_PREFIX + name;
+ },
+ getPolicy: function(spec) {
+ var policy = {}, conditions = [], bucket = spec.bucket, date = spec.date, drift = spec.clockDrift, key = spec.key, accessKey = spec.accessKey, acl = spec.acl, type = spec.type, expectedStatus = spec.expectedStatus, sessionToken = spec.sessionToken, params = spec.params, successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl), minFileSize = spec.minFileSize, maxFileSize = spec.maxFileSize, reducedRedundancy = spec.reducedRedundancy, region = spec.region, serverSideEncryption = spec.serverSideEncryption, signatureVersion = spec.signatureVersion;
+ policy.expiration = qq.s3.util.getPolicyExpirationDate(date, drift);
+ conditions.push({
+ acl: acl
+ });
+ conditions.push({
+ bucket: bucket
+ });
+ if (type) {
+ conditions.push({
+ "Content-Type": type
+ });
+ }
+ if (expectedStatus) {
+ conditions.push({
+ success_action_status: expectedStatus.toString()
+ });
+ }
+ if (successRedirectUrl) {
+ conditions.push({
+ success_action_redirect: successRedirectUrl
+ });
+ }
+ if (reducedRedundancy) {
+ conditions.push({});
+ conditions[conditions.length - 1][qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;
+ }
+ if (sessionToken) {
+ conditions.push({});
+ conditions[conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;
+ }
+ if (serverSideEncryption) {
+ conditions.push({});
+ conditions[conditions.length - 1][qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;
+ }
+ if (signatureVersion === 2) {
+ conditions.push({
+ key: key
+ });
+ } else if (signatureVersion === 4) {
+ conditions.push({});
+ conditions[conditions.length - 1][qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;
+ conditions.push({});
+ conditions[conditions.length - 1].key = key;
+ conditions.push({});
+ conditions[conditions.length - 1][qq.s3.util.CREDENTIAL_PARAM_NAME] = qq.s3.util.getV4CredentialsString({
+ date: date,
+ key: accessKey,
+ region: region
+ });
+ conditions.push({});
+ conditions[conditions.length - 1][qq.s3.util.DATE_PARAM_NAME] = qq.s3.util.getV4PolicyDate(date, drift);
+ }
+ qq.each(params, function(name, val) {
+ var awsParamName = qq.s3.util._getPrefixedParamName(name), param = {};
+ if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {
+ param[awsParamName] = val;
+ } else {
+ param[awsParamName] = encodeURIComponent(val);
+ }
+ conditions.push(param);
+ });
+ policy.conditions = conditions;
+ qq.s3.util.enforceSizeLimits(policy, minFileSize, maxFileSize);
+ return policy;
+ },
+ refreshPolicyCredentials: function(policy, newSessionToken) {
+ var sessionTokenFound = false;
+ qq.each(policy.conditions, function(oldCondIdx, oldCondObj) {
+ qq.each(oldCondObj, function(oldCondName, oldCondVal) {
+ if (oldCondName === qq.s3.util.SESSION_TOKEN_PARAM_NAME) {
+ oldCondObj[oldCondName] = newSessionToken;
+ sessionTokenFound = true;
+ }
+ });
+ });
+ if (!sessionTokenFound) {
+ policy.conditions.push({});
+ policy.conditions[policy.conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = newSessionToken;
+ }
+ },
+ generateAwsParams: function(spec, signPolicyCallback) {
+ var awsParams = {}, customParams = spec.params, promise = new qq.Promise(), sessionToken = spec.sessionToken, drift = spec.clockDrift, type = spec.type, key = spec.key, accessKey = spec.accessKey, acl = spec.acl, expectedStatus = spec.expectedStatus, successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl), reducedRedundancy = spec.reducedRedundancy, region = spec.region, serverSideEncryption = spec.serverSideEncryption, signatureVersion = spec.signatureVersion, now = new Date(), log = spec.log, policyJson;
+ spec.date = now;
+ policyJson = qq.s3.util.getPolicy(spec);
+ awsParams.key = key;
+ if (type) {
+ awsParams["Content-Type"] = type;
+ }
+ if (expectedStatus) {
+ awsParams.success_action_status = expectedStatus;
+ }
+ if (successRedirectUrl) {
+ awsParams.success_action_redirect = successRedirectUrl;
+ }
+ if (reducedRedundancy) {
+ awsParams[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;
+ }
+ if (serverSideEncryption) {
+ awsParams[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;
+ }
+ if (sessionToken) {
+ awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;
+ }
+ awsParams.acl = acl;
+ qq.each(customParams, function(name, val) {
+ var awsParamName = qq.s3.util._getPrefixedParamName(name);
+ if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {
+ awsParams[awsParamName] = val;
+ } else {
+ awsParams[awsParamName] = encodeURIComponent(val);
+ }
+ });
+ if (signatureVersion === 2) {
+ awsParams.AWSAccessKeyId = accessKey;
+ } else if (signatureVersion === 4) {
+ awsParams[qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;
+ awsParams[qq.s3.util.CREDENTIAL_PARAM_NAME] = qq.s3.util.getV4CredentialsString({
+ date: now,
+ key: accessKey,
+ region: region
+ });
+ awsParams[qq.s3.util.DATE_PARAM_NAME] = qq.s3.util.getV4PolicyDate(now, drift);
+ }
+ signPolicyCallback(policyJson).then(function(policyAndSignature, updatedAccessKey, updatedSessionToken) {
+ awsParams.policy = policyAndSignature.policy;
+ if (spec.signatureVersion === 2) {
+ awsParams.signature = policyAndSignature.signature;
+ if (updatedAccessKey) {
+ awsParams.AWSAccessKeyId = updatedAccessKey;
+ }
+ } else if (spec.signatureVersion === 4) {
+ awsParams[qq.s3.util.V4_SIGNATURE_PARAM_NAME] = policyAndSignature.signature;
+ }
+ if (updatedSessionToken) {
+ awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;
+ }
+ promise.success(awsParams);
+ }, function(errorMessage) {
+ errorMessage = errorMessage || "Can't continue further with request to S3 as we did not receive " + "a valid signature and policy from the server.";
+ log("Policy signing failed. " + errorMessage, "error");
+ promise.failure(errorMessage);
+ });
+ return promise;
+ },
+ enforceSizeLimits: function(policy, minSize, maxSize) {
+ var adjustedMinSize = minSize < 0 ? 0 : minSize, adjustedMaxSize = maxSize <= 0 ? 9007199254740992 : maxSize;
+ if (minSize > 0 || maxSize > 0) {
+ policy.conditions.push([ "content-length-range", adjustedMinSize.toString(), adjustedMaxSize.toString() ]);
+ }
+ },
+ getPolicyExpirationDate: function(date, drift) {
+ var adjustedDate = new Date(date.getTime() + drift);
+ return qq.s3.util.getPolicyDate(adjustedDate, 5);
+ },
+ getCredentialsDate: function(date) {
+ return date.getUTCFullYear() + "" + ("0" + (date.getUTCMonth() + 1)).slice(-2) + ("0" + date.getUTCDate()).slice(-2);
+ },
+ getPolicyDate: function(date, _minutesToAdd_) {
+ var minutesToAdd = _minutesToAdd_ || 0, pad, r;
+ date.setMinutes(date.getMinutes() + (minutesToAdd || 0));
+ if (Date.prototype.toISOString) {
+ return date.toISOString();
+ } else {
+ pad = function(number) {
+ r = String(number);
+ if (r.length === 1) {
+ r = "0" + r;
+ }
+ return r;
+ };
+ return date.getUTCFullYear() + "-" + pad(date.getUTCMonth() + 1) + "-" + pad(date.getUTCDate()) + "T" + pad(date.getUTCHours()) + ":" + pad(date.getUTCMinutes()) + ":" + pad(date.getUTCSeconds()) + "." + String((date.getUTCMilliseconds() / 1e3).toFixed(3)).slice(2, 5) + "Z";
+ }
+ },
+ parseIframeResponse: function(iframe) {
+ var doc = iframe.contentDocument || iframe.contentWindow.document, queryString = doc.location.search, match = /bucket=(.+)&key=(.+)&etag=(.+)/.exec(queryString);
+ if (match) {
+ return {
+ bucket: match[1],
+ key: match[2],
+ etag: match[3].replace(/%22/g, "")
+ };
+ }
+ },
+ getSuccessRedirectAbsoluteUrl: function(successRedirectUrl) {
+ if (successRedirectUrl) {
+ var targetAnchorContainer = document.createElement("div"), targetAnchor;
+ if (qq.ie7()) {
+ targetAnchorContainer.innerHTML = " ";
+ targetAnchor = targetAnchorContainer.firstChild;
+ return targetAnchor.href;
+ } else {
+ targetAnchor = document.createElement("a");
+ targetAnchor.href = successRedirectUrl;
+ targetAnchor.href = targetAnchor.href;
+ return targetAnchor.href;
+ }
+ }
+ },
+ getV4CredentialsString: function(spec) {
+ return spec.key + "/" + qq.s3.util.getCredentialsDate(spec.date) + "/" + spec.region + "/s3/aws4_request";
+ },
+ getV4PolicyDate: function(date, drift) {
+ var adjustedDate = new Date(date.getTime() + drift);
+ return qq.s3.util.getCredentialsDate(adjustedDate) + "T" + ("0" + adjustedDate.getUTCHours()).slice(-2) + ("0" + adjustedDate.getUTCMinutes()).slice(-2) + ("0" + adjustedDate.getUTCSeconds()).slice(-2) + "Z";
+ },
+ encodeQueryStringParam: function(param) {
+ var percentEncoded = encodeURIComponent(param);
+ percentEncoded = percentEncoded.replace(/[!'()]/g, escape);
+ percentEncoded = percentEncoded.replace(/\*/g, "%2A");
+ return percentEncoded.replace(/%20/g, "+");
+ },
+ uriEscape: function(string) {
+ var output = encodeURIComponent(string);
+ output = output.replace(/[^A-Za-z0-9_.~\-%]+/g, escape);
+ output = output.replace(/[*]/g, function(ch) {
+ return "%" + ch.charCodeAt(0).toString(16).toUpperCase();
+ });
+ return output;
+ },
+ uriEscapePath: function(path) {
+ var parts = [];
+ qq.each(path.split("/"), function(idx, item) {
+ parts.push(qq.s3.util.uriEscape(item));
+ });
+ return parts.join("/");
+ }
+ };
+ }();
+ (function() {
+ "use strict";
+ qq.nonTraditionalBasePublicApi = {
+ setUploadSuccessParams: function(params, id) {
+ this._uploadSuccessParamsStore.set(params, id);
+ },
+ setUploadSuccessEndpoint: function(endpoint, id) {
+ this._uploadSuccessEndpointStore.set(endpoint, id);
+ }
+ };
+ qq.nonTraditionalBasePrivateApi = {
+ _onComplete: function(id, name, result, xhr) {
+ var success = result.success ? true : false, self = this, onCompleteArgs = arguments, successEndpoint = this._uploadSuccessEndpointStore.get(id), successCustomHeaders = this._options.uploadSuccess.customHeaders, successMethod = this._options.uploadSuccess.method, cors = this._options.cors, promise = new qq.Promise(), uploadSuccessParams = this._uploadSuccessParamsStore.get(id), fileParams = this._paramsStore.get(id), onSuccessFromServer = function(successRequestResult) {
+ delete self._failedSuccessRequestCallbacks[id];
+ qq.extend(result, successRequestResult);
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.success(successRequestResult);
+ }, onFailureFromServer = function(successRequestResult) {
+ var callback = submitSuccessRequest;
+ qq.extend(result, successRequestResult);
+ if (result && result.reset) {
+ callback = null;
+ }
+ if (!callback) {
+ delete self._failedSuccessRequestCallbacks[id];
+ } else {
+ self._failedSuccessRequestCallbacks[id] = callback;
+ }
+ if (!self._onAutoRetry(id, name, result, xhr, callback)) {
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.failure(successRequestResult);
+ }
+ }, submitSuccessRequest, successAjaxRequester;
+ if (success && successEndpoint) {
+ successAjaxRequester = new qq.UploadSuccessAjaxRequester({
+ endpoint: successEndpoint,
+ method: successMethod,
+ customHeaders: successCustomHeaders,
+ cors: cors,
+ log: qq.bind(this.log, this)
+ });
+ qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);
+ fileParams && qq.extend(uploadSuccessParams, fileParams, true);
+ submitSuccessRequest = qq.bind(function() {
+ successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams).then(onSuccessFromServer, onFailureFromServer);
+ }, self);
+ submitSuccessRequest();
+ return promise;
+ }
+ return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);
+ },
+ _manualRetry: function(id) {
+ var successRequestCallback = this._failedSuccessRequestCallbacks[id];
+ return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.s3.FineUploaderBasic = function(o) {
+ var options = {
+ request: {
+ accessKey: null,
+ clockDrift: 0
+ },
+ objectProperties: {
+ acl: "private",
+ bucket: qq.bind(function(id) {
+ return qq.s3.util.getBucket(this.getEndpoint(id));
+ }, this),
+ host: qq.bind(function(id) {
+ return /(?:http|https):\/\/(.+)(?:\/.+)?/.exec(this._endpointStore.get(id))[1];
+ }, this),
+ key: "uuid",
+ reducedRedundancy: false,
+ region: "us-east-1",
+ serverSideEncryption: false
+ },
+ credentials: {
+ accessKey: null,
+ secretKey: null,
+ expiration: null,
+ sessionToken: null
+ },
+ signature: {
+ customHeaders: {},
+ endpoint: null,
+ version: 2
+ },
+ uploadSuccess: {
+ endpoint: null,
+ method: "POST",
+ params: {},
+ customHeaders: {}
+ },
+ iframeSupport: {
+ localBlankPagePath: null
+ },
+ chunking: {
+ partSize: 5242880
+ },
+ cors: {
+ allowXdr: true
+ },
+ callbacks: {
+ onCredentialsExpired: function() {}
+ }
+ };
+ qq.extend(options, o, true);
+ if (!this.setCredentials(options.credentials, true)) {
+ this._currentCredentials.accessKey = options.request.accessKey;
+ }
+ this._aclStore = this._createStore(options.objectProperties.acl);
+ qq.FineUploaderBasic.call(this, options);
+ this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);
+ this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);
+ this._failedSuccessRequestCallbacks = {};
+ this._cannedKeys = {};
+ this._cannedBuckets = {};
+ this._buckets = {};
+ this._hosts = {};
+ };
+ qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePublicApi);
+ qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePrivateApi);
+ qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);
+ qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);
+ qq.extend(qq.s3.FineUploaderBasic.prototype, {
+ getBucket: function(id) {
+ if (this._cannedBuckets[id] == null) {
+ return this._buckets[id];
+ }
+ return this._cannedBuckets[id];
+ },
+ getKey: function(id) {
+ if (this._cannedKeys[id] == null) {
+ return this._handler.getThirdPartyFileId(id);
+ }
+ return this._cannedKeys[id];
+ },
+ reset: function() {
+ qq.FineUploaderBasic.prototype.reset.call(this);
+ this._failedSuccessRequestCallbacks = [];
+ this._buckets = {};
+ this._hosts = {};
+ },
+ setCredentials: function(credentials, ignoreEmpty) {
+ if (credentials && credentials.secretKey) {
+ if (!credentials.accessKey) {
+ throw new qq.Error("Invalid credentials: no accessKey");
+ } else if (!credentials.expiration) {
+ throw new qq.Error("Invalid credentials: no expiration");
+ } else {
+ this._currentCredentials = qq.extend({}, credentials);
+ if (qq.isString(credentials.expiration)) {
+ this._currentCredentials.expiration = new Date(credentials.expiration);
+ }
+ }
+ return true;
+ } else if (!ignoreEmpty) {
+ throw new qq.Error("Invalid credentials parameter!");
+ } else {
+ this._currentCredentials = {};
+ }
+ },
+ setAcl: function(acl, id) {
+ this._aclStore.set(acl, id);
+ },
+ _createUploadHandler: function() {
+ var self = this, additionalOptions = {
+ aclStore: this._aclStore,
+ getBucket: qq.bind(this._determineBucket, this),
+ getHost: qq.bind(this._determineHost, this),
+ getKeyName: qq.bind(this._determineKeyName, this),
+ iframeSupport: this._options.iframeSupport,
+ objectProperties: this._options.objectProperties,
+ signature: this._options.signature,
+ clockDrift: this._options.request.clockDrift,
+ validation: {
+ minSizeLimit: this._options.validation.minSizeLimit,
+ maxSizeLimit: this._options.validation.sizeLimit
+ }
+ };
+ qq.override(this._endpointStore, function(super_) {
+ return {
+ get: function(id) {
+ var endpoint = super_.get(id);
+ if (endpoint.indexOf("http") < 0) {
+ return "http://" + endpoint;
+ }
+ return endpoint;
+ }
+ };
+ });
+ qq.override(this._paramsStore, function(super_) {
+ return {
+ get: function(id) {
+ var oldParams = super_.get(id), modifiedParams = {};
+ qq.each(oldParams, function(name, val) {
+ var paramName = name;
+ if (qq.indexOf(qq.s3.util.CASE_SENSITIVE_PARAM_NAMES, paramName) < 0) {
+ paramName = paramName.toLowerCase();
+ }
+ modifiedParams[paramName] = qq.isFunction(val) ? val() : val;
+ });
+ return modifiedParams;
+ }
+ };
+ });
+ additionalOptions.signature.credentialsProvider = {
+ get: function() {
+ return self._currentCredentials;
+ },
+ onExpired: function() {
+ var updateCredentials = new qq.Promise(), callbackRetVal = self._options.callbacks.onCredentialsExpired();
+ if (qq.isGenericPromise(callbackRetVal)) {
+ callbackRetVal.then(function(credentials) {
+ try {
+ self.setCredentials(credentials);
+ updateCredentials.success();
+ } catch (error) {
+ self.log("Invalid credentials returned from onCredentialsExpired callback! (" + error.message + ")", "error");
+ updateCredentials.failure("onCredentialsExpired did not return valid credentials.");
+ }
+ }, function(errorMsg) {
+ self.log("onCredentialsExpired callback indicated failure! (" + errorMsg + ")", "error");
+ updateCredentials.failure("onCredentialsExpired callback failed.");
+ });
+ } else {
+ self.log("onCredentialsExpired callback did not return a promise!", "error");
+ updateCredentials.failure("Unexpected return value for onCredentialsExpired.");
+ }
+ return updateCredentials;
+ }
+ };
+ return qq.FineUploaderBasic.prototype._createUploadHandler.call(this, additionalOptions, "s3");
+ },
+ _determineObjectPropertyValue: function(id, property) {
+ var maybe = this._options.objectProperties[property], promise = new qq.Promise(), self = this;
+ if (qq.isFunction(maybe)) {
+ maybe = maybe(id);
+ if (qq.isGenericPromise(maybe)) {
+ promise = maybe;
+ } else {
+ promise.success(maybe);
+ }
+ } else if (qq.isString(maybe)) {
+ promise.success(maybe);
+ }
+ promise.then(function success(value) {
+ self["_" + property + "s"][id] = value;
+ }, function failure(errorMsg) {
+ qq.log("Problem determining " + property + " for ID " + id + " (" + errorMsg + ")", "error");
+ });
+ return promise;
+ },
+ _determineBucket: function(id) {
+ return this._determineObjectPropertyValue(id, "bucket");
+ },
+ _determineHost: function(id) {
+ return this._determineObjectPropertyValue(id, "host");
+ },
+ _determineKeyName: function(id, filename) {
+ var promise = new qq.Promise(), keynameLogic = this._options.objectProperties.key, extension = qq.getExtension(filename), onGetKeynameFailure = promise.failure, onGetKeynameSuccess = function(keyname, extension) {
+ var keynameToUse = keyname;
+ if (extension !== undefined) {
+ keynameToUse += "." + extension;
+ }
+ promise.success(keynameToUse);
+ };
+ switch (keynameLogic) {
+ case "uuid":
+ onGetKeynameSuccess(this.getUuid(id), extension);
+ break;
+
+ case "filename":
+ onGetKeynameSuccess(filename);
+ break;
+
+ default:
+ if (qq.isFunction(keynameLogic)) {
+ this._handleKeynameFunction(keynameLogic, id, onGetKeynameSuccess, onGetKeynameFailure);
+ } else {
+ this.log(keynameLogic + " is not a valid value for the s3.keyname option!", "error");
+ onGetKeynameFailure();
+ }
+ }
+ return promise;
+ },
+ _handleKeynameFunction: function(keynameFunc, id, successCallback, failureCallback) {
+ var self = this, onSuccess = function(keyname) {
+ successCallback(keyname);
+ }, onFailure = function(reason) {
+ self.log(qq.format("Failed to retrieve key name for {}. Reason: {}", id, reason || "null"), "error");
+ failureCallback(reason);
+ }, keyname = keynameFunc.call(this, id);
+ if (qq.isGenericPromise(keyname)) {
+ keyname.then(onSuccess, onFailure);
+ } else if (keyname == null) {
+ onFailure();
+ } else {
+ onSuccess(keyname);
+ }
+ },
+ _getEndpointSpecificParams: function(id, response, maybeXhr) {
+ var params = {
+ key: this.getKey(id),
+ uuid: this.getUuid(id),
+ name: this.getName(id),
+ bucket: this.getBucket(id)
+ };
+ if (maybeXhr && maybeXhr.getResponseHeader("ETag")) {
+ params.etag = maybeXhr.getResponseHeader("ETag");
+ } else if (response.etag) {
+ params.etag = response.etag;
+ }
+ return params;
+ },
+ _onSubmitDelete: function(id, onSuccessCallback) {
+ var additionalMandatedParams = {
+ key: this.getKey(id),
+ bucket: this.getBucket(id)
+ };
+ return qq.FineUploaderBasic.prototype._onSubmitDelete.call(this, id, onSuccessCallback, additionalMandatedParams);
+ },
+ _addCannedFile: function(sessionData) {
+ var id;
+ if (sessionData.s3Key == null) {
+ throw new qq.Error("Did not find s3Key property in server session response. This is required!");
+ } else {
+ id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);
+ this._cannedKeys[id] = sessionData.s3Key;
+ this._cannedBuckets[id] = sessionData.s3Bucket;
+ }
+ return id;
+ }
+ });
+ })();
+ if (!window.Uint8ClampedArray) {
+ window.Uint8ClampedArray = function() {};
+ }
+ qq.s3.RequestSigner = function(o) {
+ "use strict";
+ var requester, thisSignatureRequester = this, pendingSignatures = {}, options = {
+ expectingPolicy: false,
+ method: "POST",
+ signatureSpec: {
+ drift: 0,
+ credentialsProvider: {},
+ endpoint: null,
+ customHeaders: {},
+ version: 2
+ },
+ maxConnections: 3,
+ endpointStore: {},
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {}
+ }, credentialsProvider, generateHeaders = function(signatureConstructor, signature, promise) {
+ var headers = signatureConstructor.getHeaders();
+ if (options.signatureSpec.version === 4) {
+ headers.Authorization = qq.s3.util.V4_ALGORITHM_PARAM_VALUE + " Credential=" + options.signatureSpec.credentialsProvider.get().accessKey + "/" + qq.s3.util.getCredentialsDate(signatureConstructor.getRequestDate()) + "/" + options.signatureSpec.region + "/" + "s3/aws4_request," + "SignedHeaders=" + signatureConstructor.getSignedHeaders() + "," + "Signature=" + signature;
+ } else {
+ headers.Authorization = "AWS " + options.signatureSpec.credentialsProvider.get().accessKey + ":" + signature;
+ }
+ promise.success(headers, signatureConstructor.getEndOfUrl());
+ }, v2 = {
+ getStringToSign: function(signatureSpec) {
+ return qq.format("{}\n{}\n{}\n\n{}/{}/{}", signatureSpec.method, signatureSpec.contentMd5 || "", signatureSpec.contentType || "", signatureSpec.headersStr || "\n", signatureSpec.bucket, signatureSpec.endOfUrl);
+ },
+ signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {
+ var headersWordArray = qq.CryptoJS.enc.Utf8.parse(headersStr), headersHmacSha1 = qq.CryptoJS.HmacSHA1(headersWordArray, credentialsProvider.get().secretKey), headersHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(headersHmacSha1);
+ generateHeaders(signatureConstructor, headersHmacSha1Base64, signatureEffort);
+ },
+ signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {
+ var policyStr = JSON.stringify(policy), policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr), base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray), policyHmacSha1 = qq.CryptoJS.HmacSHA1(base64Policy, credentialsProvider.get().secretKey), policyHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(policyHmacSha1);
+ signatureEffort.success({
+ policy: base64Policy,
+ signature: policyHmacSha1Base64
+ }, updatedAccessKey, updatedSessionToken);
+ }
+ }, v4 = {
+ getCanonicalQueryString: function(endOfUri) {
+ var queryParamIdx = endOfUri.indexOf("?"), canonicalQueryString = "", encodedQueryParams, encodedQueryParamNames, queryStrings;
+ if (queryParamIdx >= 0) {
+ encodedQueryParams = {};
+ queryStrings = endOfUri.substr(queryParamIdx + 1).split("&");
+ qq.each(queryStrings, function(idx, queryString) {
+ var nameAndVal = queryString.split("="), paramVal = nameAndVal[1];
+ if (paramVal == null) {
+ paramVal = "";
+ }
+ encodedQueryParams[encodeURIComponent(nameAndVal[0])] = encodeURIComponent(paramVal);
+ });
+ encodedQueryParamNames = Object.keys(encodedQueryParams).sort();
+ encodedQueryParamNames.forEach(function(encodedQueryParamName, idx) {
+ canonicalQueryString += encodedQueryParamName + "=" + encodedQueryParams[encodedQueryParamName];
+ if (idx < encodedQueryParamNames.length - 1) {
+ canonicalQueryString += "&";
+ }
+ });
+ }
+ return canonicalQueryString;
+ },
+ getCanonicalRequest: function(signatureSpec) {
+ return qq.format("{}\n{}\n{}\n{}\n{}\n{}", signatureSpec.method, v4.getCanonicalUri(signatureSpec.endOfUrl), v4.getCanonicalQueryString(signatureSpec.endOfUrl), signatureSpec.headersStr || "\n", v4.getSignedHeaders(signatureSpec.headerNames), signatureSpec.hashedContent);
+ },
+ getCanonicalUri: function(endOfUri) {
+ var path = endOfUri, queryParamIdx = endOfUri.indexOf("?");
+ if (queryParamIdx > 0) {
+ path = endOfUri.substr(0, queryParamIdx);
+ }
+ return "/" + path;
+ },
+ getEncodedHashedPayload: function(body) {
+ var promise = new qq.Promise(), reader;
+ if (qq.isBlob(body)) {
+ reader = new FileReader();
+ reader.onloadend = function(e) {
+ if (e.target.readyState === FileReader.DONE) {
+ if (e.target.error) {
+ promise.failure(e.target.error);
+ } else {
+ var wordArray = qq.CryptoJS.lib.WordArray.create(e.target.result);
+ promise.success(qq.CryptoJS.SHA256(wordArray).toString());
+ }
+ }
+ };
+ reader.readAsArrayBuffer(body);
+ } else {
+ body = body || "";
+ promise.success(qq.CryptoJS.SHA256(body).toString());
+ }
+ return promise;
+ },
+ getScope: function(date, region) {
+ return qq.s3.util.getCredentialsDate(date) + "/" + region + "/s3/aws4_request";
+ },
+ getStringToSign: function(signatureSpec) {
+ var canonicalRequest = v4.getCanonicalRequest(signatureSpec), date = qq.s3.util.getV4PolicyDate(signatureSpec.date, signatureSpec.drift), hashedRequest = qq.CryptoJS.SHA256(canonicalRequest).toString(), scope = v4.getScope(signatureSpec.date, options.signatureSpec.region), stringToSignTemplate = "AWS4-HMAC-SHA256\n{}\n{}\n{}";
+ return {
+ hashed: qq.format(stringToSignTemplate, date, scope, hashedRequest),
+ raw: qq.format(stringToSignTemplate, date, scope, canonicalRequest)
+ };
+ },
+ getSignedHeaders: function(headerNames) {
+ var signedHeaders = "";
+ headerNames.forEach(function(headerName, idx) {
+ signedHeaders += headerName.toLowerCase();
+ if (idx < headerNames.length - 1) {
+ signedHeaders += ";";
+ }
+ });
+ return signedHeaders;
+ },
+ signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {
+ var secretKey = credentialsProvider.get().secretKey, headersPattern = /.+\n.+\n(\d+)\/(.+)\/s3\/.+\n(.+)/, matches = headersPattern.exec(headersStr), dateKey, dateRegionKey, dateRegionServiceKey, signingKey;
+ dateKey = qq.CryptoJS.HmacSHA256(matches[1], "AWS4" + secretKey);
+ dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);
+ dateRegionServiceKey = qq.CryptoJS.HmacSHA256("s3", dateRegionKey);
+ signingKey = qq.CryptoJS.HmacSHA256("aws4_request", dateRegionServiceKey);
+ generateHeaders(signatureConstructor, qq.CryptoJS.HmacSHA256(headersStr, signingKey), signatureEffort);
+ },
+ signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {
+ var policyStr = JSON.stringify(policy), policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr), base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray), secretKey = credentialsProvider.get().secretKey, credentialPattern = /.+\/(.+)\/(.+)\/s3\/aws4_request/, credentialCondition = function() {
+ var credential = null;
+ qq.each(policy.conditions, function(key, condition) {
+ var val = condition["x-amz-credential"];
+ if (val) {
+ credential = val;
+ return false;
+ }
+ });
+ return credential;
+ }(), matches, dateKey, dateRegionKey, dateRegionServiceKey, signingKey;
+ matches = credentialPattern.exec(credentialCondition);
+ dateKey = qq.CryptoJS.HmacSHA256(matches[1], "AWS4" + secretKey);
+ dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);
+ dateRegionServiceKey = qq.CryptoJS.HmacSHA256("s3", dateRegionKey);
+ signingKey = qq.CryptoJS.HmacSHA256("aws4_request", dateRegionServiceKey);
+ signatureEffort.success({
+ policy: base64Policy,
+ signature: qq.CryptoJS.HmacSHA256(base64Policy, signingKey).toString()
+ }, updatedAccessKey, updatedSessionToken);
+ }
+ };
+ qq.extend(options, o, true);
+ credentialsProvider = options.signatureSpec.credentialsProvider;
+ function handleSignatureReceived(id, xhrOrXdr, isError) {
+ var responseJson = xhrOrXdr.responseText, pendingSignatureData = pendingSignatures[id], promise = pendingSignatureData.promise, signatureConstructor = pendingSignatureData.signatureConstructor, errorMessage, response;
+ delete pendingSignatures[id];
+ if (responseJson) {
+ try {
+ response = qq.parseJson(responseJson);
+ } catch (error) {
+ options.log("Error attempting to parse signature response: " + error, "error");
+ }
+ }
+ if (response && response.error) {
+ isError = true;
+ errorMessage = response.error;
+ } else if (response && response.invalid) {
+ isError = true;
+ errorMessage = "Invalid policy document or request headers!";
+ } else if (response) {
+ if (options.expectingPolicy && !response.policy) {
+ isError = true;
+ errorMessage = "Response does not include the base64 encoded policy!";
+ } else if (!response.signature) {
+ isError = true;
+ errorMessage = "Response does not include the signature!";
+ }
+ } else {
+ isError = true;
+ errorMessage = "Received an empty or invalid response from the server!";
+ }
+ if (isError) {
+ if (errorMessage) {
+ options.log(errorMessage, "error");
+ }
+ promise.failure(errorMessage);
+ } else if (signatureConstructor) {
+ generateHeaders(signatureConstructor, response.signature, promise);
+ } else {
+ promise.success(response);
+ }
+ }
+ function getStringToSignArtifacts(id, version, requestInfo) {
+ var promise = new qq.Promise(), method = "POST", headerNames = [], headersStr = "", now = new Date(), endOfUrl, signatureSpec, toSign, generateStringToSign = function(requestInfo) {
+ var contentMd5, headerIndexesToRemove = [];
+ qq.each(requestInfo.headers, function(name) {
+ headerNames.push(name);
+ });
+ headerNames.sort();
+ qq.each(headerNames, function(idx, headerName) {
+ if (qq.indexOf(qq.s3.util.UNSIGNABLE_REST_HEADER_NAMES, headerName) < 0) {
+ headersStr += headerName.toLowerCase() + ":" + requestInfo.headers[headerName].trim() + "\n";
+ } else if (headerName === "Content-MD5") {
+ contentMd5 = requestInfo.headers[headerName];
+ } else {
+ headerIndexesToRemove.unshift(idx);
+ }
+ });
+ qq.each(headerIndexesToRemove, function(idx, headerIdx) {
+ headerNames.splice(headerIdx, 1);
+ });
+ signatureSpec = {
+ bucket: requestInfo.bucket,
+ contentMd5: contentMd5,
+ contentType: requestInfo.contentType,
+ date: now,
+ drift: options.signatureSpec.drift,
+ endOfUrl: endOfUrl,
+ hashedContent: requestInfo.hashedContent,
+ headerNames: headerNames,
+ headersStr: headersStr,
+ method: method
+ };
+ toSign = version === 2 ? v2.getStringToSign(signatureSpec) : v4.getStringToSign(signatureSpec);
+ return {
+ date: now,
+ endOfUrl: endOfUrl,
+ signedHeaders: version === 4 ? v4.getSignedHeaders(signatureSpec.headerNames) : null,
+ toSign: version === 4 ? toSign.hashed : toSign,
+ toSignRaw: version === 4 ? toSign.raw : toSign
+ };
+ };
+ switch (requestInfo.type) {
+ case thisSignatureRequester.REQUEST_TYPE.MULTIPART_ABORT:
+ method = "DELETE";
+ endOfUrl = qq.format("uploadId={}", requestInfo.uploadId);
+ break;
+
+ case thisSignatureRequester.REQUEST_TYPE.MULTIPART_INITIATE:
+ endOfUrl = "uploads";
+ break;
+
+ case thisSignatureRequester.REQUEST_TYPE.MULTIPART_COMPLETE:
+ endOfUrl = qq.format("uploadId={}", requestInfo.uploadId);
+ break;
+
+ case thisSignatureRequester.REQUEST_TYPE.MULTIPART_UPLOAD:
+ method = "PUT";
+ endOfUrl = qq.format("partNumber={}&uploadId={}", requestInfo.partNum, requestInfo.uploadId);
+ break;
+ }
+ endOfUrl = requestInfo.key + "?" + endOfUrl;
+ if (version === 4) {
+ v4.getEncodedHashedPayload(requestInfo.content).then(function(hashedContent) {
+ requestInfo.headers["x-amz-content-sha256"] = hashedContent;
+ requestInfo.headers.Host = requestInfo.host;
+ requestInfo.headers["x-amz-date"] = qq.s3.util.getV4PolicyDate(now, options.signatureSpec.drift);
+ requestInfo.hashedContent = hashedContent;
+ promise.success(generateStringToSign(requestInfo));
+ }, function(err) {
+ promise.failure(err);
+ });
+ } else {
+ promise.success(generateStringToSign(requestInfo));
+ }
+ return promise;
+ }
+ function determineSignatureClientSide(id, toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken) {
+ var updatedHeaders;
+ if (toBeSigned.signatureConstructor) {
+ if (updatedSessionToken) {
+ updatedHeaders = toBeSigned.signatureConstructor.getHeaders();
+ updatedHeaders[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;
+ toBeSigned.signatureConstructor.withHeaders(updatedHeaders);
+ }
+ toBeSigned.signatureConstructor.getToSign(id).then(function(signatureArtifacts) {
+ signApiRequest(toBeSigned.signatureConstructor, signatureArtifacts.stringToSign, signatureEffort);
+ }, function(err) {
+ signatureEffort.failure(err);
+ });
+ } else {
+ updatedSessionToken && qq.s3.util.refreshPolicyCredentials(toBeSigned, updatedSessionToken);
+ signPolicy(toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken);
+ }
+ }
+ function signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {
+ if (options.signatureSpec.version === 4) {
+ v4.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);
+ } else {
+ v2.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);
+ }
+ }
+ function signApiRequest(signatureConstructor, headersStr, signatureEffort) {
+ if (options.signatureSpec.version === 4) {
+ v4.signApiRequest(signatureConstructor, headersStr, signatureEffort);
+ } else {
+ v2.signApiRequest(signatureConstructor, headersStr, signatureEffort);
+ }
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ method: options.method,
+ contentType: "application/json; charset=utf-8",
+ endpointStore: {
+ get: function() {
+ return options.signatureSpec.endpoint;
+ }
+ },
+ paramsStore: options.paramsStore,
+ maxConnections: options.maxConnections,
+ customHeaders: options.signatureSpec.customHeaders,
+ log: options.log,
+ onComplete: handleSignatureReceived,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ getSignature: function(id, toBeSigned) {
+ var params = toBeSigned, signatureConstructor = toBeSigned.signatureConstructor, signatureEffort = new qq.Promise(), queryParams;
+ if (options.signatureSpec.version === 4) {
+ queryParams = {
+ v4: true
+ };
+ }
+ if (credentialsProvider.get().secretKey && qq.CryptoJS) {
+ if (credentialsProvider.get().expiration.getTime() > Date.now()) {
+ determineSignatureClientSide(id, toBeSigned, signatureEffort);
+ } else {
+ credentialsProvider.onExpired().then(function() {
+ determineSignatureClientSide(id, toBeSigned, signatureEffort, credentialsProvider.get().accessKey, credentialsProvider.get().sessionToken);
+ }, function(errorMsg) {
+ options.log("Attempt to update expired credentials apparently failed! Unable to sign request. ", "error");
+ signatureEffort.failure("Unable to sign request - expired credentials.");
+ });
+ }
+ } else {
+ options.log("Submitting S3 signature request for " + id);
+ if (signatureConstructor) {
+ signatureConstructor.getToSign(id).then(function(signatureArtifacts) {
+ params = {
+ headers: signatureArtifacts.stringToSignRaw
+ };
+ requester.initTransport(id).withParams(params).withQueryParams(queryParams).send();
+ }, function(err) {
+ options.log("Failed to construct signature. ", "error");
+ signatureEffort.failure("Failed to construct signature.");
+ });
+ } else {
+ requester.initTransport(id).withParams(params).withQueryParams(queryParams).send();
+ }
+ pendingSignatures[id] = {
+ promise: signatureEffort,
+ signatureConstructor: signatureConstructor
+ };
+ }
+ return signatureEffort;
+ },
+ constructStringToSign: function(type, bucket, host, key) {
+ var headers = {}, uploadId, content, contentType, partNum, artifacts;
+ return {
+ withHeaders: function(theHeaders) {
+ headers = theHeaders;
+ return this;
+ },
+ withUploadId: function(theUploadId) {
+ uploadId = theUploadId;
+ return this;
+ },
+ withContent: function(theContent) {
+ content = theContent;
+ return this;
+ },
+ withContentType: function(theContentType) {
+ contentType = theContentType;
+ return this;
+ },
+ withPartNum: function(thePartNum) {
+ partNum = thePartNum;
+ return this;
+ },
+ getToSign: function(id) {
+ var sessionToken = credentialsProvider.get().sessionToken, promise = new qq.Promise(), adjustedDate = new Date(Date.now() + options.signatureSpec.drift);
+ headers["x-amz-date"] = adjustedDate.toUTCString();
+ if (sessionToken) {
+ headers[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;
+ }
+ getStringToSignArtifacts(id, options.signatureSpec.version, {
+ bucket: bucket,
+ content: content,
+ contentType: contentType,
+ headers: headers,
+ host: host,
+ key: key,
+ partNum: partNum,
+ type: type,
+ uploadId: uploadId
+ }).then(function(_artifacts_) {
+ artifacts = _artifacts_;
+ promise.success({
+ headers: function() {
+ if (contentType) {
+ headers["Content-Type"] = contentType;
+ }
+ delete headers.Host;
+ return headers;
+ }(),
+ date: artifacts.date,
+ endOfUrl: artifacts.endOfUrl,
+ signedHeaders: artifacts.signedHeaders,
+ stringToSign: artifacts.toSign,
+ stringToSignRaw: artifacts.toSignRaw
+ });
+ }, function(err) {
+ promise.failure(err);
+ });
+ return promise;
+ },
+ getHeaders: function() {
+ return qq.extend({}, headers);
+ },
+ getEndOfUrl: function() {
+ return artifacts && artifacts.endOfUrl;
+ },
+ getRequestDate: function() {
+ return artifacts && artifacts.date;
+ },
+ getSignedHeaders: function() {
+ return artifacts && artifacts.signedHeaders;
+ }
+ };
+ }
+ });
+ };
+ qq.s3.RequestSigner.prototype.REQUEST_TYPE = {
+ MULTIPART_INITIATE: "multipart_initiate",
+ MULTIPART_COMPLETE: "multipart_complete",
+ MULTIPART_ABORT: "multipart_abort",
+ MULTIPART_UPLOAD: "multipart_upload"
+ };
+ qq.UploadSuccessAjaxRequester = function(o) {
+ "use strict";
+ var requester, pendingRequests = [], options = {
+ method: "POST",
+ endpoint: null,
+ maxConnections: 3,
+ customHeaders: {},
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {}
+ };
+ qq.extend(options, o);
+ function handleSuccessResponse(id, xhrOrXdr, isError) {
+ var promise = pendingRequests[id], responseJson = xhrOrXdr.responseText, successIndicator = {
+ success: true
+ }, failureIndicator = {
+ success: false
+ }, parsedResponse;
+ delete pendingRequests[id];
+ options.log(qq.format("Received the following response body to an upload success request for id {}: {}", id, responseJson));
+ try {
+ parsedResponse = qq.parseJson(responseJson);
+ if (isError || parsedResponse && (parsedResponse.error || parsedResponse.success === false)) {
+ options.log("Upload success request was rejected by the server.", "error");
+ promise.failure(qq.extend(parsedResponse, failureIndicator));
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(qq.extend(parsedResponse, successIndicator));
+ }
+ } catch (error) {
+ if (isError) {
+ options.log(qq.format("Your server indicated failure in its upload success request response for id {}!", id), "error");
+ promise.failure(failureIndicator);
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(successIndicator);
+ }
+ }
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ method: options.method,
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ paramsStore: options.paramsStore,
+ maxConnections: options.maxConnections,
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: handleSuccessResponse,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendSuccessRequest: function(id, spec) {
+ var promise = new qq.Promise();
+ options.log("Submitting upload success request/notification for " + id);
+ requester.initTransport(id).withParams(spec).send();
+ pendingRequests[id] = promise;
+ return promise;
+ }
+ });
+ };
+ qq.s3.InitiateMultipartAjaxRequester = function(o) {
+ "use strict";
+ var requester, pendingInitiateRequests = {}, options = {
+ filenameParam: "qqfilename",
+ method: "POST",
+ endpointStore: null,
+ paramsStore: null,
+ signatureSpec: null,
+ aclStore: null,
+ reducedRedundancy: false,
+ serverSideEncryption: false,
+ maxConnections: 3,
+ getContentType: function(id) {},
+ getBucket: function(id) {},
+ getHost: function(id) {},
+ getKey: function(id) {},
+ getName: function(id) {},
+ log: function(str, level) {}
+ }, getSignatureAjaxRequester;
+ qq.extend(options, o);
+ getSignatureAjaxRequester = new qq.s3.RequestSigner({
+ endpointStore: options.endpointStore,
+ signatureSpec: options.signatureSpec,
+ cors: options.cors,
+ log: options.log
+ });
+ function getHeaders(id) {
+ var bucket = options.getBucket(id), host = options.getHost(id), headers = {}, promise = new qq.Promise(), key = options.getKey(id), signatureConstructor;
+ headers["x-amz-acl"] = options.aclStore.get(id);
+ if (options.reducedRedundancy) {
+ headers[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;
+ }
+ if (options.serverSideEncryption) {
+ headers[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;
+ }
+ headers[qq.s3.util.AWS_PARAM_PREFIX + options.filenameParam] = encodeURIComponent(options.getName(id));
+ qq.each(options.paramsStore.get(id), function(name, val) {
+ if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {
+ headers[name] = val;
+ } else {
+ headers[qq.s3.util.AWS_PARAM_PREFIX + name] = encodeURIComponent(val);
+ }
+ });
+ signatureConstructor = getSignatureAjaxRequester.constructStringToSign(getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_INITIATE, bucket, host, key).withContentType(options.getContentType(id)).withHeaders(headers);
+ getSignatureAjaxRequester.getSignature(id, {
+ signatureConstructor: signatureConstructor
+ }).then(promise.success, promise.failure);
+ return promise;
+ }
+ function handleInitiateRequestComplete(id, xhr, isError) {
+ var promise = pendingInitiateRequests[id], domParser = new DOMParser(), responseDoc = domParser.parseFromString(xhr.responseText, "application/xml"), uploadIdElements, messageElements, uploadId, errorMessage, status;
+ delete pendingInitiateRequests[id];
+ if (isError) {
+ status = xhr.status;
+ messageElements = responseDoc.getElementsByTagName("Message");
+ if (messageElements.length > 0) {
+ errorMessage = messageElements[0].textContent;
+ }
+ } else {
+ uploadIdElements = responseDoc.getElementsByTagName("UploadId");
+ if (uploadIdElements.length > 0) {
+ uploadId = uploadIdElements[0].textContent;
+ } else {
+ errorMessage = "Upload ID missing from request";
+ }
+ }
+ if (uploadId === undefined) {
+ if (errorMessage) {
+ options.log(qq.format("Specific problem detected initiating multipart upload request for {}: '{}'.", id, errorMessage), "error");
+ } else {
+ options.log(qq.format("Unexplained error with initiate multipart upload request for {}. Status code {}.", id, status), "error");
+ }
+ promise.failure("Problem initiating upload request.", xhr);
+ } else {
+ options.log(qq.format("Initiate multipart upload request successful for {}. Upload ID is {}", id, uploadId));
+ promise.success(uploadId, xhr);
+ }
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ method: options.method,
+ contentType: null,
+ endpointStore: options.endpointStore,
+ maxConnections: options.maxConnections,
+ allowXRequestedWithAndCacheControl: false,
+ log: options.log,
+ onComplete: handleInitiateRequestComplete,
+ successfulResponseCodes: {
+ POST: [ 200 ]
+ }
+ }));
+ qq.extend(this, {
+ send: function(id) {
+ var promise = new qq.Promise();
+ getHeaders(id).then(function(headers, endOfUrl) {
+ options.log("Submitting S3 initiate multipart upload request for " + id);
+ pendingInitiateRequests[id] = promise;
+ requester.initTransport(id).withPath(endOfUrl).withHeaders(headers).send();
+ }, promise.failure);
+ return promise;
+ }
+ });
+ };
+ qq.s3.CompleteMultipartAjaxRequester = function(o) {
+ "use strict";
+ var requester, pendingCompleteRequests = {}, options = {
+ method: "POST",
+ contentType: "text/xml",
+ endpointStore: null,
+ signatureSpec: null,
+ maxConnections: 3,
+ getBucket: function(id) {},
+ getHost: function(id) {},
+ getKey: function(id) {},
+ log: function(str, level) {}
+ }, getSignatureAjaxRequester;
+ qq.extend(options, o);
+ getSignatureAjaxRequester = new qq.s3.RequestSigner({
+ endpointStore: options.endpointStore,
+ signatureSpec: options.signatureSpec,
+ cors: options.cors,
+ log: options.log
+ });
+ function getHeaders(id, uploadId, body) {
+ var headers = {}, promise = new qq.Promise(), bucket = options.getBucket(id), host = options.getHost(id), signatureConstructor = getSignatureAjaxRequester.constructStringToSign(getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_COMPLETE, bucket, host, options.getKey(id)).withUploadId(uploadId).withContent(body).withContentType("application/xml; charset=UTF-8");
+ getSignatureAjaxRequester.getSignature(id, {
+ signatureConstructor: signatureConstructor
+ }).then(promise.success, promise.failure);
+ return promise;
+ }
+ function handleCompleteRequestComplete(id, xhr, isError) {
+ var promise = pendingCompleteRequests[id], domParser = new DOMParser(), bucket = options.getBucket(id), key = options.getKey(id), responseDoc = domParser.parseFromString(xhr.responseText, "application/xml"), bucketEls = responseDoc.getElementsByTagName("Bucket"), keyEls = responseDoc.getElementsByTagName("Key");
+ delete pendingCompleteRequests[id];
+ options.log(qq.format("Complete response status {}, body = {}", xhr.status, xhr.responseText));
+ if (isError) {
+ options.log(qq.format("Complete Multipart Upload request for {} failed with status {}.", id, xhr.status), "error");
+ } else {
+ if (bucketEls.length && keyEls.length) {
+ if (bucketEls[0].textContent !== bucket) {
+ isError = true;
+ options.log(qq.format("Wrong bucket in response to Complete Multipart Upload request for {}.", id), "error");
+ }
+ } else {
+ isError = true;
+ options.log(qq.format("Missing bucket and/or key in response to Complete Multipart Upload request for {}.", id), "error");
+ }
+ }
+ if (isError) {
+ promise.failure("Problem combining the file parts!", xhr);
+ } else {
+ promise.success({}, xhr);
+ }
+ }
+ function getCompleteRequestBody(etagEntries) {
+ var doc = document.implementation.createDocument(null, "CompleteMultipartUpload", null);
+ etagEntries.sort(function(a, b) {
+ return a.part - b.part;
+ });
+ qq.each(etagEntries, function(idx, etagEntry) {
+ var part = etagEntry.part, etag = etagEntry.etag, partEl = doc.createElement("Part"), partNumEl = doc.createElement("PartNumber"), partNumTextEl = doc.createTextNode(part), etagTextEl = doc.createTextNode(etag), etagEl = doc.createElement("ETag");
+ etagEl.appendChild(etagTextEl);
+ partNumEl.appendChild(partNumTextEl);
+ partEl.appendChild(partNumEl);
+ partEl.appendChild(etagEl);
+ qq(doc).children()[0].appendChild(partEl);
+ });
+ return new XMLSerializer().serializeToString(doc);
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ method: options.method,
+ contentType: "application/xml; charset=UTF-8",
+ endpointStore: options.endpointStore,
+ maxConnections: options.maxConnections,
+ allowXRequestedWithAndCacheControl: false,
+ log: options.log,
+ onComplete: handleCompleteRequestComplete,
+ successfulResponseCodes: {
+ POST: [ 200 ]
+ }
+ }));
+ qq.extend(this, {
+ send: function(id, uploadId, etagEntries) {
+ var promise = new qq.Promise(), body = getCompleteRequestBody(etagEntries);
+ getHeaders(id, uploadId, body).then(function(headers, endOfUrl) {
+ options.log("Submitting S3 complete multipart upload request for " + id);
+ pendingCompleteRequests[id] = promise;
+ delete headers["Content-Type"];
+ requester.initTransport(id).withPath(endOfUrl).withHeaders(headers).withPayload(body).send();
+ }, promise.failure);
+ return promise;
+ }
+ });
+ };
+ qq.s3.AbortMultipartAjaxRequester = function(o) {
+ "use strict";
+ var requester, options = {
+ method: "DELETE",
+ endpointStore: null,
+ signatureSpec: null,
+ maxConnections: 3,
+ getBucket: function(id) {},
+ getHost: function(id) {},
+ getKey: function(id) {},
+ log: function(str, level) {}
+ }, getSignatureAjaxRequester;
+ qq.extend(options, o);
+ getSignatureAjaxRequester = new qq.s3.RequestSigner({
+ endpointStore: options.endpointStore,
+ signatureSpec: options.signatureSpec,
+ cors: options.cors,
+ log: options.log
+ });
+ function getHeaders(id, uploadId) {
+ var headers = {}, promise = new qq.Promise(), bucket = options.getBucket(id), host = options.getHost(id), signatureConstructor = getSignatureAjaxRequester.constructStringToSign(getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, options.getKey(id)).withUploadId(uploadId);
+ getSignatureAjaxRequester.getSignature(id, {
+ signatureConstructor: signatureConstructor
+ }).then(promise.success, promise.failure);
+ return promise;
+ }
+ function handleAbortRequestComplete(id, xhr, isError) {
+ var domParser = new DOMParser(), responseDoc = domParser.parseFromString(xhr.responseText, "application/xml"), errorEls = responseDoc.getElementsByTagName("Error"), awsErrorMsg;
+ options.log(qq.format("Abort response status {}, body = {}", xhr.status, xhr.responseText));
+ if (isError) {
+ options.log(qq.format("Abort Multipart Upload request for {} failed with status {}.", id, xhr.status), "error");
+ } else {
+ if (errorEls.length) {
+ isError = true;
+ awsErrorMsg = responseDoc.getElementsByTagName("Message")[0].textContent;
+ options.log(qq.format("Failed to Abort Multipart Upload request for {}. Error: {}", id, awsErrorMsg), "error");
+ } else {
+ options.log(qq.format("Abort MPU request succeeded for file ID {}.", id));
+ }
+ }
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ "DELETE" ],
+ method: options.method,
+ contentType: null,
+ endpointStore: options.endpointStore,
+ maxConnections: options.maxConnections,
+ allowXRequestedWithAndCacheControl: false,
+ log: options.log,
+ onComplete: handleAbortRequestComplete,
+ successfulResponseCodes: {
+ DELETE: [ 204 ]
+ }
+ }));
+ qq.extend(this, {
+ send: function(id, uploadId) {
+ getHeaders(id, uploadId).then(function(headers, endOfUrl) {
+ options.log("Submitting S3 Abort multipart upload request for " + id);
+ requester.initTransport(id).withPath(endOfUrl).withHeaders(headers).send();
+ });
+ }
+ });
+ };
+ qq.s3.XhrUploadHandler = function(spec, proxy) {
+ "use strict";
+ var getName = proxy.getName, log = proxy.log, clockDrift = spec.clockDrift, expectedStatus = 200, onGetBucket = spec.getBucket, onGetHost = spec.getHost, onGetKeyName = spec.getKeyName, filenameParam = spec.filenameParam, paramsStore = spec.paramsStore, endpointStore = spec.endpointStore, aclStore = spec.aclStore, reducedRedundancy = spec.objectProperties.reducedRedundancy, region = spec.objectProperties.region, serverSideEncryption = spec.objectProperties.serverSideEncryption, validation = spec.validation, signature = qq.extend({
+ region: region,
+ drift: clockDrift
+ }, spec.signature), handler = this, credentialsProvider = spec.signature.credentialsProvider, chunked = {
+ combine: function(id) {
+ var uploadId = handler._getPersistableData(id).uploadId, etagMap = handler._getPersistableData(id).etags, result = new qq.Promise();
+ requesters.completeMultipart.send(id, uploadId, etagMap).then(result.success, function failure(reason, xhr) {
+ result.failure(upload.done(id, xhr).response, xhr);
+ });
+ return result;
+ },
+ done: function(id, xhr, chunkIdx) {
+ var response = upload.response.parse(id, xhr), etag;
+ if (response.success) {
+ etag = xhr.getResponseHeader("ETag");
+ if (!handler._getPersistableData(id).etags) {
+ handler._getPersistableData(id).etags = [];
+ }
+ handler._getPersistableData(id).etags.push({
+ part: chunkIdx + 1,
+ etag: etag
+ });
+ }
+ },
+ initHeaders: function(id, chunkIdx, blob) {
+ var headers = {}, bucket = upload.bucket.getName(id), host = upload.host.getName(id), key = upload.key.urlSafe(id), promise = new qq.Promise(), signatureConstructor = requesters.restSignature.constructStringToSign(requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key).withPartNum(chunkIdx + 1).withContent(blob).withUploadId(handler._getPersistableData(id).uploadId);
+ requesters.restSignature.getSignature(id + "." + chunkIdx, {
+ signatureConstructor: signatureConstructor
+ }).then(promise.success, promise.failure);
+ return promise;
+ },
+ put: function(id, chunkIdx) {
+ var xhr = handler._createXhr(id, chunkIdx), chunkData = handler._getChunkData(id, chunkIdx), domain = spec.endpointStore.get(id), promise = new qq.Promise();
+ chunked.initHeaders(id, chunkIdx, chunkData.blob).then(function(headers, endOfUrl) {
+ if (xhr._cancelled) {
+ log(qq.format("Upload of item {}.{} cancelled. Upload will not start after successful signature request.", id, chunkIdx));
+ promise.failure({
+ error: "Chunk upload cancelled"
+ });
+ } else {
+ var url = domain + "/" + endOfUrl;
+ handler._registerProgressHandler(id, chunkIdx, chunkData.size);
+ upload.track(id, xhr, chunkIdx).then(promise.success, promise.failure);
+ xhr.open("PUT", url, true);
+ qq.each(headers, function(name, val) {
+ xhr.setRequestHeader(name, val);
+ });
+ xhr.send(chunkData.blob);
+ }
+ }, function() {
+ promise.failure({
+ error: "Problem signing the chunk!"
+ }, xhr);
+ });
+ return promise;
+ },
+ send: function(id, chunkIdx) {
+ var promise = new qq.Promise();
+ chunked.setup(id).then(function() {
+ chunked.put(id, chunkIdx).then(promise.success, promise.failure);
+ }, function(errorMessage, xhr) {
+ promise.failure({
+ error: errorMessage
+ }, xhr);
+ });
+ return promise;
+ },
+ setup: function(id) {
+ var promise = new qq.Promise(), uploadId = handler._getPersistableData(id).uploadId, uploadIdPromise = new qq.Promise();
+ if (!uploadId) {
+ handler._getPersistableData(id).uploadId = uploadIdPromise;
+ requesters.initiateMultipart.send(id).then(function(uploadId) {
+ handler._getPersistableData(id).uploadId = uploadId;
+ uploadIdPromise.success(uploadId);
+ promise.success(uploadId);
+ }, function(errorMsg, xhr) {
+ handler._getPersistableData(id).uploadId = null;
+ promise.failure(errorMsg, xhr);
+ uploadIdPromise.failure(errorMsg, xhr);
+ });
+ } else if (uploadId instanceof qq.Promise) {
+ uploadId.then(function(uploadId) {
+ promise.success(uploadId);
+ });
+ } else {
+ promise.success(uploadId);
+ }
+ return promise;
+ }
+ }, requesters = {
+ abortMultipart: new qq.s3.AbortMultipartAjaxRequester({
+ endpointStore: endpointStore,
+ signatureSpec: signature,
+ cors: spec.cors,
+ log: log,
+ getBucket: function(id) {
+ return upload.bucket.getName(id);
+ },
+ getHost: function(id) {
+ return upload.host.getName(id);
+ },
+ getKey: function(id) {
+ return upload.key.urlSafe(id);
+ }
+ }),
+ completeMultipart: new qq.s3.CompleteMultipartAjaxRequester({
+ endpointStore: endpointStore,
+ signatureSpec: signature,
+ cors: spec.cors,
+ log: log,
+ getBucket: function(id) {
+ return upload.bucket.getName(id);
+ },
+ getHost: function(id) {
+ return upload.host.getName(id);
+ },
+ getKey: function(id) {
+ return upload.key.urlSafe(id);
+ }
+ }),
+ initiateMultipart: new qq.s3.InitiateMultipartAjaxRequester({
+ filenameParam: filenameParam,
+ endpointStore: endpointStore,
+ paramsStore: paramsStore,
+ signatureSpec: signature,
+ aclStore: aclStore,
+ reducedRedundancy: reducedRedundancy,
+ serverSideEncryption: serverSideEncryption,
+ cors: spec.cors,
+ log: log,
+ getContentType: function(id) {
+ return handler._getMimeType(id);
+ },
+ getBucket: function(id) {
+ return upload.bucket.getName(id);
+ },
+ getHost: function(id) {
+ return upload.host.getName(id);
+ },
+ getKey: function(id) {
+ return upload.key.urlSafe(id);
+ },
+ getName: function(id) {
+ return getName(id);
+ }
+ }),
+ policySignature: new qq.s3.RequestSigner({
+ expectingPolicy: true,
+ signatureSpec: signature,
+ cors: spec.cors,
+ log: log
+ }),
+ restSignature: new qq.s3.RequestSigner({
+ endpointStore: endpointStore,
+ signatureSpec: signature,
+ cors: spec.cors,
+ log: log
+ })
+ }, simple = {
+ initParams: function(id) {
+ var customParams = paramsStore.get(id);
+ customParams[filenameParam] = getName(id);
+ return qq.s3.util.generateAwsParams({
+ endpoint: endpointStore.get(id),
+ clockDrift: clockDrift,
+ params: customParams,
+ type: handler._getMimeType(id),
+ bucket: upload.bucket.getName(id),
+ key: handler.getThirdPartyFileId(id),
+ accessKey: credentialsProvider.get().accessKey,
+ sessionToken: credentialsProvider.get().sessionToken,
+ acl: aclStore.get(id),
+ expectedStatus: expectedStatus,
+ minFileSize: validation.minSizeLimit,
+ maxFileSize: validation.maxSizeLimit,
+ reducedRedundancy: reducedRedundancy,
+ region: region,
+ serverSideEncryption: serverSideEncryption,
+ signatureVersion: signature.version,
+ log: log
+ }, qq.bind(requesters.policySignature.getSignature, this, id));
+ },
+ send: function(id) {
+ var promise = new qq.Promise(), xhr = handler._createXhr(id), fileOrBlob = handler.getFile(id);
+ handler._registerProgressHandler(id);
+ upload.track(id, xhr).then(promise.success, promise.failure);
+ simple.setup(id, xhr, fileOrBlob).then(function(toSend) {
+ log("Sending upload request for " + id);
+ xhr.send(toSend);
+ }, promise.failure);
+ return promise;
+ },
+ setup: function(id, xhr, fileOrBlob) {
+ var formData = new FormData(), endpoint = endpointStore.get(id), url = endpoint, promise = new qq.Promise();
+ simple.initParams(id).then(function(awsParams) {
+ xhr.open("POST", url, true);
+ qq.obj2FormData(awsParams, formData);
+ formData.append("file", fileOrBlob);
+ promise.success(formData);
+ }, function(errorMessage) {
+ promise.failure({
+ error: errorMessage
+ });
+ });
+ return promise;
+ }
+ }, upload = {
+ bucket: {
+ promise: function(id) {
+ var promise = new qq.Promise(), cachedBucket = handler._getFileState(id).bucket;
+ if (cachedBucket) {
+ promise.success(cachedBucket);
+ } else {
+ onGetBucket(id).then(function(bucket) {
+ handler._getFileState(id).bucket = bucket;
+ promise.success(bucket);
+ }, promise.failure);
+ }
+ return promise;
+ },
+ getName: function(id) {
+ return handler._getFileState(id).bucket;
+ }
+ },
+ host: {
+ promise: function(id) {
+ var promise = new qq.Promise(), cachedHost = handler._getFileState(id).host;
+ if (cachedHost) {
+ promise.success(cachedHost);
+ } else {
+ onGetHost(id).then(function(host) {
+ handler._getFileState(id).host = host;
+ promise.success(host);
+ }, promise.failure);
+ }
+ return promise;
+ },
+ getName: function(id) {
+ return handler._getFileState(id).host;
+ }
+ },
+ done: function(id, xhr) {
+ var response = upload.response.parse(id, xhr), isError = response.success !== true;
+ if (isError && upload.response.shouldReset(response.code)) {
+ log("This is an unrecoverable error, we must restart the upload entirely on the next retry attempt.", "error");
+ response.reset = true;
+ }
+ return {
+ success: !isError,
+ response: response
+ };
+ },
+ key: {
+ promise: function(id) {
+ var promise = new qq.Promise(), key = handler.getThirdPartyFileId(id);
+ if (key == null) {
+ handler._setThirdPartyFileId(id, promise);
+ onGetKeyName(id, getName(id)).then(function(keyName) {
+ handler._setThirdPartyFileId(id, keyName);
+ promise.success(keyName);
+ }, function(errorReason) {
+ handler._setThirdPartyFileId(id, null);
+ promise.failure(errorReason);
+ });
+ } else if (qq.isGenericPromise(key)) {
+ key.then(promise.success, promise.failure);
+ } else {
+ promise.success(key);
+ }
+ return promise;
+ },
+ urlSafe: function(id) {
+ var encodedKey = handler.getThirdPartyFileId(id);
+ return qq.s3.util.uriEscapePath(encodedKey);
+ }
+ },
+ response: {
+ parse: function(id, xhr) {
+ var response = {}, parsedErrorProps;
+ try {
+ log(qq.format("Received response status {} with body: {}", xhr.status, xhr.responseText));
+ if (xhr.status === expectedStatus) {
+ response.success = true;
+ } else {
+ parsedErrorProps = upload.response.parseError(xhr.responseText);
+ if (parsedErrorProps) {
+ response.error = parsedErrorProps.message;
+ response.code = parsedErrorProps.code;
+ }
+ }
+ } catch (error) {
+ log("Error when attempting to parse xhr response text (" + error.message + ")", "error");
+ }
+ return response;
+ },
+ parseError: function(awsResponseXml) {
+ var parser = new DOMParser(), parsedDoc = parser.parseFromString(awsResponseXml, "application/xml"), errorEls = parsedDoc.getElementsByTagName("Error"), errorDetails = {}, codeEls, messageEls;
+ if (errorEls.length) {
+ codeEls = parsedDoc.getElementsByTagName("Code");
+ messageEls = parsedDoc.getElementsByTagName("Message");
+ if (messageEls.length) {
+ errorDetails.message = messageEls[0].textContent;
+ }
+ if (codeEls.length) {
+ errorDetails.code = codeEls[0].textContent;
+ }
+ return errorDetails;
+ }
+ },
+ shouldReset: function(errorCode) {
+ return errorCode === "EntityTooSmall" || errorCode === "InvalidPart" || errorCode === "InvalidPartOrder" || errorCode === "NoSuchUpload";
+ }
+ },
+ start: function(id, optChunkIdx) {
+ var promise = new qq.Promise();
+ upload.key.promise(id).then(function() {
+ upload.bucket.promise(id).then(function() {
+ upload.host.promise(id).then(function() {
+ if (optChunkIdx == null) {
+ simple.send(id).then(promise.success, promise.failure);
+ } else {
+ chunked.send(id, optChunkIdx).then(promise.success, promise.failure);
+ }
+ });
+ });
+ }, function(errorReason) {
+ promise.failure({
+ error: errorReason
+ });
+ });
+ return promise;
+ },
+ track: function(id, xhr, optChunkIdx) {
+ var promise = new qq.Promise();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4) {
+ var result;
+ if (optChunkIdx == null) {
+ result = upload.done(id, xhr);
+ promise[result.success ? "success" : "failure"](result.response, xhr);
+ } else {
+ chunked.done(id, xhr, optChunkIdx);
+ result = upload.done(id, xhr);
+ promise[result.success ? "success" : "failure"](result.response, xhr);
+ }
+ }
+ };
+ return promise;
+ }
+ };
+ qq.extend(this, {
+ uploadChunk: upload.start,
+ uploadFile: upload.start
+ });
+ qq.extend(this, new qq.XhrUploadHandler({
+ options: qq.extend({
+ namespace: "s3"
+ }, spec),
+ proxy: qq.extend({
+ getEndpoint: spec.endpointStore.get
+ }, proxy)
+ }));
+ qq.override(this, function(super_) {
+ return {
+ expunge: function(id) {
+ var uploadId = handler._getPersistableData(id) && handler._getPersistableData(id).uploadId, existedInLocalStorage = handler._maybeDeletePersistedChunkData(id);
+ if (uploadId !== undefined && existedInLocalStorage) {
+ requesters.abortMultipart.send(id, uploadId);
+ }
+ super_.expunge(id);
+ },
+ finalizeChunks: function(id) {
+ return chunked.combine(id);
+ },
+ _getLocalStorageId: function(id) {
+ var baseStorageId = super_._getLocalStorageId(id), bucketName = upload.bucket.getName(id);
+ return baseStorageId + "-" + bucketName;
+ }
+ };
+ });
+ };
+ qq.s3.FormUploadHandler = function(options, proxy) {
+ "use strict";
+ var handler = this, clockDrift = options.clockDrift, onUuidChanged = proxy.onUuidChanged, getName = proxy.getName, getUuid = proxy.getUuid, log = proxy.log, onGetBucket = options.getBucket, onGetKeyName = options.getKeyName, filenameParam = options.filenameParam, paramsStore = options.paramsStore, endpointStore = options.endpointStore, aclStore = options.aclStore, reducedRedundancy = options.objectProperties.reducedRedundancy, region = options.objectProperties.region, serverSideEncryption = options.objectProperties.serverSideEncryption, validation = options.validation, signature = options.signature, successRedirectUrl = options.iframeSupport.localBlankPagePath, credentialsProvider = options.signature.credentialsProvider, getSignatureAjaxRequester = new qq.s3.RequestSigner({
+ signatureSpec: signature,
+ cors: options.cors,
+ log: log
+ });
+ if (successRedirectUrl === undefined) {
+ throw new Error("successRedirectEndpoint MUST be defined if you intend to use browsers that do not support the File API!");
+ }
+ function isValidResponse(id, iframe) {
+ var response, endpoint = options.endpointStore.get(id), bucket = handler._getFileState(id).bucket, doc, innerHtml, responseData;
+ try {
+ doc = iframe.contentDocument || iframe.contentWindow.document;
+ innerHtml = doc.body.innerHTML;
+ responseData = qq.s3.util.parseIframeResponse(iframe);
+ if (responseData.bucket === bucket && responseData.key === qq.s3.util.encodeQueryStringParam(handler.getThirdPartyFileId(id))) {
+ return true;
+ }
+ log("Response from AWS included an unexpected bucket or key name.", "error");
+ } catch (error) {
+ log("Error when attempting to parse form upload response (" + error.message + ")", "error");
+ }
+ return false;
+ }
+ function generateAwsParams(id) {
+ var customParams = paramsStore.get(id);
+ customParams[filenameParam] = getName(id);
+ return qq.s3.util.generateAwsParams({
+ endpoint: endpointStore.get(id),
+ clockDrift: clockDrift,
+ params: customParams,
+ bucket: handler._getFileState(id).bucket,
+ key: handler.getThirdPartyFileId(id),
+ accessKey: credentialsProvider.get().accessKey,
+ sessionToken: credentialsProvider.get().sessionToken,
+ acl: aclStore.get(id),
+ minFileSize: validation.minSizeLimit,
+ maxFileSize: validation.maxSizeLimit,
+ successRedirectUrl: successRedirectUrl,
+ reducedRedundancy: reducedRedundancy,
+ region: region,
+ serverSideEncryption: serverSideEncryption,
+ signatureVersion: signature.version,
+ log: log
+ }, qq.bind(getSignatureAjaxRequester.getSignature, this, id));
+ }
+ function createForm(id, iframe) {
+ var promise = new qq.Promise(), method = "POST", endpoint = options.endpointStore.get(id), fileName = getName(id);
+ generateAwsParams(id).then(function(params) {
+ var form = handler._initFormForUpload({
+ method: method,
+ endpoint: endpoint,
+ params: params,
+ paramsInBody: true,
+ targetName: iframe.name
+ });
+ promise.success(form);
+ }, function(errorMessage) {
+ promise.failure(errorMessage);
+ handleFinishedUpload(id, iframe, fileName, {
+ error: errorMessage
+ });
+ });
+ return promise;
+ }
+ function handleUpload(id) {
+ var iframe = handler._createIframe(id), input = handler.getInput(id), promise = new qq.Promise();
+ createForm(id, iframe).then(function(form) {
+ form.appendChild(input);
+ handler._attachLoadEvent(iframe, function(response) {
+ log("iframe loaded");
+ if (response) {
+ if (response.success === false) {
+ log("Amazon likely rejected the upload request", "error");
+ promise.failure(response);
+ }
+ } else {
+ response = {};
+ response.success = isValidResponse(id, iframe);
+ if (response.success === false) {
+ log("A success response was received by Amazon, but it was invalid in some way.", "error");
+ promise.failure(response);
+ } else {
+ qq.extend(response, qq.s3.util.parseIframeResponse(iframe));
+ promise.success(response);
+ }
+ }
+ handleFinishedUpload(id, iframe);
+ });
+ log("Sending upload request for " + id);
+ form.submit();
+ qq(form).remove();
+ }, promise.failure);
+ return promise;
+ }
+ function handleFinishedUpload(id, iframe) {
+ handler._detachLoadEvent(id);
+ iframe && qq(iframe).remove();
+ }
+ qq.extend(this, new qq.FormUploadHandler({
+ options: {
+ isCors: false,
+ inputName: "file"
+ },
+ proxy: {
+ onCancel: options.onCancel,
+ onUuidChanged: onUuidChanged,
+ getName: getName,
+ getUuid: getUuid,
+ log: log
+ }
+ }));
+ qq.extend(this, {
+ uploadFile: function(id) {
+ var name = getName(id), promise = new qq.Promise();
+ if (handler.getThirdPartyFileId(id)) {
+ if (handler._getFileState(id).bucket) {
+ handleUpload(id).then(promise.success, promise.failure);
+ } else {
+ onGetBucket(id).then(function(bucket) {
+ handler._getFileState(id).bucket = bucket;
+ handleUpload(id).then(promise.success, promise.failure);
+ });
+ }
+ } else {
+ onGetKeyName(id, name).then(function(key) {
+ onGetBucket(id).then(function(bucket) {
+ handler._getFileState(id).bucket = bucket;
+ handler._setThirdPartyFileId(id, key);
+ handleUpload(id).then(promise.success, promise.failure);
+ }, function(errorReason) {
+ promise.failure({
+ error: errorReason
+ });
+ });
+ }, function(errorReason) {
+ promise.failure({
+ error: errorReason
+ });
+ });
+ }
+ return promise;
+ }
+ });
+ };
+ (function() {
+ "use strict";
+ qq.s3.FineUploader = function(o) {
+ var options = {
+ failedUploadTextDisplay: {
+ mode: "custom"
+ }
+ };
+ qq.extend(options, o, true);
+ qq.FineUploader.call(this, options, "s3");
+ if (!qq.supportedFeatures.ajaxUploading && options.iframeSupport.localBlankPagePath === undefined) {
+ this._options.element.innerHTML = "You MUST set the localBlankPagePath
property " + "of the iframeSupport
option since this browser does not support the File API!
";
+ }
+ };
+ qq.extend(qq.s3.FineUploader.prototype, qq.s3.FineUploaderBasic.prototype);
+ qq.extend(qq.s3.FineUploader.prototype, qq.uiPublicApi);
+ qq.extend(qq.s3.FineUploader.prototype, qq.uiPrivateApi);
+ })();
+ qq.azure = qq.azure || {};
+ qq.azure.util = qq.azure.util || function() {
+ "use strict";
+ return {
+ AZURE_PARAM_PREFIX: "x-ms-meta-",
+ _paramNameMatchesAzureParameter: function(name) {
+ switch (name) {
+ case "Cache-Control":
+ case "Content-Disposition":
+ case "Content-Encoding":
+ case "Content-MD5":
+ case "x-ms-blob-content-encoding":
+ case "x-ms-blob-content-disposition":
+ case "x-ms-blob-content-md5":
+ case "x-ms-blob-cache-control":
+ return true;
+
+ default:
+ return false;
+ }
+ },
+ _getPrefixedParamName: function(name) {
+ if (qq.azure.util._paramNameMatchesAzureParameter(name)) {
+ return name;
+ } else {
+ return qq.azure.util.AZURE_PARAM_PREFIX + name;
+ }
+ },
+ getParamsAsHeaders: function(params) {
+ var headers = {};
+ qq.each(params, function(name, val) {
+ var headerName = qq.azure.util._getPrefixedParamName(name), value = null;
+ if (qq.isFunction(val)) {
+ value = String(val());
+ } else if (qq.isObject(val)) {
+ qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));
+ } else {
+ value = String(val);
+ }
+ if (value !== null) {
+ if (qq.azure.util._paramNameMatchesAzureParameter(name)) {
+ headers[headerName] = value;
+ } else {
+ headers[headerName] = encodeURIComponent(value);
+ }
+ }
+ });
+ return headers;
+ },
+ parseAzureError: function(responseText, log) {
+ var domParser = new DOMParser(), responseDoc = domParser.parseFromString(responseText, "application/xml"), errorTag = responseDoc.getElementsByTagName("Error")[0], errorDetails = {}, codeTag, messageTag;
+ log("Received error response: " + responseText, "error");
+ if (errorTag) {
+ messageTag = errorTag.getElementsByTagName("Message")[0];
+ if (messageTag) {
+ errorDetails.message = messageTag.textContent;
+ }
+ codeTag = errorTag.getElementsByTagName("Code")[0];
+ if (codeTag) {
+ errorDetails.code = codeTag.textContent;
+ }
+ log("Parsed Azure error: " + JSON.stringify(errorDetails), "error");
+ return errorDetails;
+ }
+ }
+ };
+ }();
+ (function() {
+ "use strict";
+ qq.nonTraditionalBasePublicApi = {
+ setUploadSuccessParams: function(params, id) {
+ this._uploadSuccessParamsStore.set(params, id);
+ },
+ setUploadSuccessEndpoint: function(endpoint, id) {
+ this._uploadSuccessEndpointStore.set(endpoint, id);
+ }
+ };
+ qq.nonTraditionalBasePrivateApi = {
+ _onComplete: function(id, name, result, xhr) {
+ var success = result.success ? true : false, self = this, onCompleteArgs = arguments, successEndpoint = this._uploadSuccessEndpointStore.get(id), successCustomHeaders = this._options.uploadSuccess.customHeaders, successMethod = this._options.uploadSuccess.method, cors = this._options.cors, promise = new qq.Promise(), uploadSuccessParams = this._uploadSuccessParamsStore.get(id), fileParams = this._paramsStore.get(id), onSuccessFromServer = function(successRequestResult) {
+ delete self._failedSuccessRequestCallbacks[id];
+ qq.extend(result, successRequestResult);
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.success(successRequestResult);
+ }, onFailureFromServer = function(successRequestResult) {
+ var callback = submitSuccessRequest;
+ qq.extend(result, successRequestResult);
+ if (result && result.reset) {
+ callback = null;
+ }
+ if (!callback) {
+ delete self._failedSuccessRequestCallbacks[id];
+ } else {
+ self._failedSuccessRequestCallbacks[id] = callback;
+ }
+ if (!self._onAutoRetry(id, name, result, xhr, callback)) {
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.failure(successRequestResult);
+ }
+ }, submitSuccessRequest, successAjaxRequester;
+ if (success && successEndpoint) {
+ successAjaxRequester = new qq.UploadSuccessAjaxRequester({
+ endpoint: successEndpoint,
+ method: successMethod,
+ customHeaders: successCustomHeaders,
+ cors: cors,
+ log: qq.bind(this.log, this)
+ });
+ qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);
+ fileParams && qq.extend(uploadSuccessParams, fileParams, true);
+ submitSuccessRequest = qq.bind(function() {
+ successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams).then(onSuccessFromServer, onFailureFromServer);
+ }, self);
+ submitSuccessRequest();
+ return promise;
+ }
+ return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);
+ },
+ _manualRetry: function(id) {
+ var successRequestCallback = this._failedSuccessRequestCallbacks[id];
+ return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.azure.FineUploaderBasic = function(o) {
+ if (!qq.supportedFeatures.ajaxUploading) {
+ throw new qq.Error("Uploading directly to Azure is not possible in this browser.");
+ }
+ var options = {
+ signature: {
+ endpoint: null,
+ customHeaders: {}
+ },
+ blobProperties: {
+ name: "uuid"
+ },
+ uploadSuccess: {
+ endpoint: null,
+ method: "POST",
+ params: {},
+ customHeaders: {}
+ },
+ chunking: {
+ partSize: 4e6,
+ minFileSize: 4000001
+ }
+ };
+ qq.extend(options, o, true);
+ qq.FineUploaderBasic.call(this, options);
+ this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);
+ this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);
+ this._failedSuccessRequestCallbacks = {};
+ this._cannedBlobNames = {};
+ };
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, {
+ getBlobName: function(id) {
+ if (this._cannedBlobNames[id] == null) {
+ return this._handler.getThirdPartyFileId(id);
+ }
+ return this._cannedBlobNames[id];
+ },
+ _getEndpointSpecificParams: function(id) {
+ return {
+ blob: this.getBlobName(id),
+ uuid: this.getUuid(id),
+ name: this.getName(id),
+ container: this._endpointStore.get(id)
+ };
+ },
+ _createUploadHandler: function() {
+ return qq.FineUploaderBasic.prototype._createUploadHandler.call(this, {
+ signature: this._options.signature,
+ onGetBlobName: qq.bind(this._determineBlobName, this),
+ deleteBlob: qq.bind(this._deleteBlob, this, true)
+ }, "azure");
+ },
+ _determineBlobName: function(id) {
+ var self = this, blobNameOptionValue = this._options.blobProperties.name, uuid = this.getUuid(id), filename = this.getName(id), fileExtension = qq.getExtension(filename), blobNameToUse = uuid;
+ if (qq.isString(blobNameOptionValue)) {
+ switch (blobNameOptionValue) {
+ case "uuid":
+ if (fileExtension !== undefined) {
+ blobNameToUse += "." + fileExtension;
+ }
+ return new qq.Promise().success(blobNameToUse);
+
+ case "filename":
+ return new qq.Promise().success(filename);
+
+ default:
+ return new qq.Promise.failure("Invalid blobName option value - " + blobNameOptionValue);
+ }
+ } else {
+ return blobNameOptionValue.call(this, id);
+ }
+ },
+ _addCannedFile: function(sessionData) {
+ var id;
+ if (sessionData.blobName == null) {
+ throw new qq.Error("Did not find blob name property in server session response. This is required!");
+ } else {
+ id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);
+ this._cannedBlobNames[id] = sessionData.blobName;
+ }
+ return id;
+ },
+ _deleteBlob: function(relatedToCancel, id) {
+ var self = this, deleteBlobSasUri = {}, blobUriStore = {
+ get: function(id) {
+ return self._endpointStore.get(id) + "/" + self.getBlobName(id);
+ }
+ }, deleteFileEndpointStore = {
+ get: function(id) {
+ return deleteBlobSasUri[id];
+ }
+ }, getSasSuccess = function(id, sasUri) {
+ deleteBlobSasUri[id] = sasUri;
+ deleteBlob.send(id);
+ }, getSasFailure = function(id, reason, xhr) {
+ if (relatedToCancel) {
+ self.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS", "error");
+ qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));
+ } else {
+ self._onDeleteComplete(id, xhr, true);
+ self._options.callbacks.onDeleteComplete(id, xhr, true);
+ }
+ }, deleteBlob = new qq.azure.DeleteBlob({
+ endpointStore: deleteFileEndpointStore,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ delete deleteBlobSasUri[id];
+ if (isError) {
+ if (relatedToCancel) {
+ self.log("Will cancel upload, but failed to remove uncommitted parts from Azure.", "error");
+ } else {
+ qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));
+ }
+ }
+ if (relatedToCancel) {
+ qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));
+ self.log("Deleted uncommitted blob chunks for " + id);
+ } else {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ }
+ }), getSas = new qq.azure.GetSas({
+ cors: this._options.cors,
+ customHeaders: this._options.signature.customHeaders,
+ endpointStore: {
+ get: function() {
+ return self._options.signature.endpoint;
+ }
+ },
+ restRequestVerb: deleteBlob.method,
+ log: qq.bind(self.log, self)
+ });
+ getSas.request(id, blobUriStore.get(id)).then(qq.bind(getSasSuccess, self, id), qq.bind(getSasFailure, self, id));
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return {
+ sendDelete: function(id, uuid) {
+ self._deleteBlob(false, id);
+ }
+ };
+ }
+ });
+ })();
+ qq.azure.XhrUploadHandler = function(spec, proxy) {
+ "use strict";
+ var handler = this, log = proxy.log, cors = spec.cors, endpointStore = spec.endpointStore, paramsStore = spec.paramsStore, signature = spec.signature, filenameParam = spec.filenameParam, minFileSizeForChunking = spec.chunking.minFileSize, deleteBlob = spec.deleteBlob, onGetBlobName = spec.onGetBlobName, getName = proxy.getName, getSize = proxy.getSize, getBlobMetadata = function(id) {
+ var params = paramsStore.get(id);
+ params[filenameParam] = getName(id);
+ return params;
+ }, api = {
+ putBlob: new qq.azure.PutBlob({
+ getBlobMetadata: getBlobMetadata,
+ log: log
+ }),
+ putBlock: new qq.azure.PutBlock({
+ log: log
+ }),
+ putBlockList: new qq.azure.PutBlockList({
+ getBlobMetadata: getBlobMetadata,
+ log: log
+ }),
+ getSasForPutBlobOrBlock: new qq.azure.GetSas({
+ cors: cors,
+ customHeaders: signature.customHeaders,
+ endpointStore: {
+ get: function() {
+ return signature.endpoint;
+ }
+ },
+ log: log,
+ restRequestVerb: "PUT"
+ })
+ };
+ function combineChunks(id) {
+ var promise = new qq.Promise();
+ getSignedUrl(id).then(function(sasUri) {
+ var mimeType = handler._getMimeType(id), blockIdEntries = handler._getPersistableData(id).blockIdEntries;
+ api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {
+ handler._registerXhr(id, null, xhr, api.putBlockList);
+ }).then(function(xhr) {
+ log("Success combining chunks for id " + id);
+ promise.success({}, xhr);
+ }, function(xhr) {
+ log("Attempt to combine chunks failed for id " + id, "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ }
+ function determineBlobUrl(id) {
+ var containerUrl = endpointStore.get(id), promise = new qq.Promise(), getBlobNameSuccess = function(blobName) {
+ handler._setThirdPartyFileId(id, blobName);
+ promise.success(containerUrl + "/" + blobName);
+ }, getBlobNameFailure = function(reason) {
+ promise.failure(reason);
+ };
+ onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);
+ return promise;
+ }
+ function getSignedUrl(id, optChunkIdx) {
+ var getSasId = optChunkIdx == null ? id : id + "." + optChunkIdx, promise = new qq.Promise(), getSasSuccess = function(sasUri) {
+ log("GET SAS request succeeded.");
+ promise.success(sasUri);
+ }, getSasFailure = function(reason, getSasXhr) {
+ log("GET SAS request failed: " + reason, "error");
+ promise.failure({
+ error: "Problem communicating with local server"
+ }, getSasXhr);
+ }, determineBlobUrlSuccess = function(blobUrl) {
+ api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(getSasSuccess, getSasFailure);
+ }, determineBlobUrlFailure = function(reason) {
+ log(qq.format("Failed to determine blob name for ID {} - {}", id, reason), "error");
+ promise.failure({
+ error: reason
+ });
+ };
+ determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);
+ return promise;
+ }
+ function handleFailure(xhr, promise) {
+ var azureError = qq.azure.util.parseAzureError(xhr.responseText, log), errorMsg = "Problem sending file to Azure";
+ promise.failure({
+ error: errorMsg,
+ azureError: azureError && azureError.message,
+ reset: xhr.status === 403
+ });
+ }
+ qq.extend(this, {
+ uploadChunk: function(id, chunkIdx) {
+ var promise = new qq.Promise();
+ getSignedUrl(id, chunkIdx).then(function(sasUri) {
+ var xhr = handler._createXhr(id, chunkIdx), chunkData = handler._getChunkData(id, chunkIdx);
+ handler._registerProgressHandler(id, chunkIdx, chunkData.size);
+ handler._registerXhr(id, chunkIdx, xhr, api.putBlock);
+ api.putBlock.upload(id + "." + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(function(blockIdEntry) {
+ if (!handler._getPersistableData(id).blockIdEntries) {
+ handler._getPersistableData(id).blockIdEntries = [];
+ }
+ handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);
+ log("Put Block call succeeded for " + id);
+ promise.success({}, xhr);
+ }, function() {
+ log(qq.format("Put Block call failed for ID {} on part {}", id, chunkIdx), "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ },
+ uploadFile: function(id) {
+ var promise = new qq.Promise(), fileOrBlob = handler.getFile(id);
+ getSignedUrl(id).then(function(sasUri) {
+ var xhr = handler._createXhr(id);
+ handler._registerProgressHandler(id);
+ api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(function() {
+ log("Put Blob call succeeded for " + id);
+ promise.success({}, xhr);
+ }, function() {
+ log("Put Blob call failed for " + id, "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ }
+ });
+ qq.extend(this, new qq.XhrUploadHandler({
+ options: qq.extend({
+ namespace: "azure"
+ }, spec),
+ proxy: qq.extend({
+ getEndpoint: spec.endpointStore.get
+ }, proxy)
+ }));
+ qq.override(this, function(super_) {
+ return {
+ expunge: function(id) {
+ var relatedToCancel = handler._wasCanceled(id), chunkingData = handler._getPersistableData(id), blockIdEntries = chunkingData && chunkingData.blockIdEntries || [];
+ if (relatedToCancel && blockIdEntries.length > 0) {
+ deleteBlob(id);
+ }
+ super_.expunge(id);
+ },
+ finalizeChunks: function(id) {
+ return combineChunks(id);
+ },
+ _shouldChunkThisFile: function(id) {
+ var maybePossible = super_._shouldChunkThisFile(id);
+ return maybePossible && getSize(id) >= minFileSizeForChunking;
+ }
+ };
+ });
+ };
+ qq.azure.GetSas = function(o) {
+ "use strict";
+ var requester, options = {
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ customHeaders: {},
+ restRequestVerb: "PUT",
+ endpointStore: null,
+ log: function(str, level) {}
+ }, requestPromises = {};
+ qq.extend(options, o);
+ function sasResponseReceived(id, xhr, isError) {
+ var promise = requestPromises[id];
+ if (isError) {
+ promise.failure("Received response code " + xhr.status, xhr);
+ } else {
+ if (xhr.responseText.length) {
+ promise.success(xhr.responseText);
+ } else {
+ promise.failure("Empty response.", xhr);
+ }
+ }
+ delete requestPromises[id];
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ successfulResponseCodes: {
+ GET: [ 200 ]
+ },
+ contentType: null,
+ customHeaders: options.customHeaders,
+ endpointStore: options.endpointStore,
+ cors: options.cors,
+ log: options.log,
+ onComplete: sasResponseReceived
+ }));
+ qq.extend(this, {
+ request: function(id, blobUri) {
+ var requestPromise = new qq.Promise(), restVerb = options.restRequestVerb;
+ options.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.", restVerb, id));
+ requestPromises[id] = requestPromise;
+ requester.initTransport(id).withParams({
+ bloburi: blobUri,
+ _method: restVerb
+ }).withCacheBuster().send();
+ return requestPromise;
+ }
+ });
+ };
+ qq.UploadSuccessAjaxRequester = function(o) {
+ "use strict";
+ var requester, pendingRequests = [], options = {
+ method: "POST",
+ endpoint: null,
+ maxConnections: 3,
+ customHeaders: {},
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {}
+ };
+ qq.extend(options, o);
+ function handleSuccessResponse(id, xhrOrXdr, isError) {
+ var promise = pendingRequests[id], responseJson = xhrOrXdr.responseText, successIndicator = {
+ success: true
+ }, failureIndicator = {
+ success: false
+ }, parsedResponse;
+ delete pendingRequests[id];
+ options.log(qq.format("Received the following response body to an upload success request for id {}: {}", id, responseJson));
+ try {
+ parsedResponse = qq.parseJson(responseJson);
+ if (isError || parsedResponse && (parsedResponse.error || parsedResponse.success === false)) {
+ options.log("Upload success request was rejected by the server.", "error");
+ promise.failure(qq.extend(parsedResponse, failureIndicator));
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(qq.extend(parsedResponse, successIndicator));
+ }
+ } catch (error) {
+ if (isError) {
+ options.log(qq.format("Your server indicated failure in its upload success request response for id {}!", id), "error");
+ promise.failure(failureIndicator);
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(successIndicator);
+ }
+ }
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ method: options.method,
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ paramsStore: options.paramsStore,
+ maxConnections: options.maxConnections,
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: handleSuccessResponse,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendSuccessRequest: function(id, spec) {
+ var promise = new qq.Promise();
+ options.log("Submitting upload success request/notification for " + id);
+ requester.initTransport(id).withParams(spec).send();
+ pendingRequests[id] = promise;
+ return promise;
+ }
+ });
+ };
+ qq.azure.DeleteBlob = function(o) {
+ "use strict";
+ var requester, method = "DELETE", options = {
+ endpointStore: {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhr, isError) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 202 ];
+ return codes;
+ }(),
+ contentType: null,
+ endpointStore: options.endpointStore,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete
+ }));
+ qq.extend(this, {
+ method: method,
+ send: function(id) {
+ options.log("Submitting Delete Blob request for " + id);
+ return requester.initTransport(id).send();
+ }
+ });
+ };
+ qq.azure.PutBlob = function(o) {
+ "use strict";
+ var requester, method = "PUT", options = {
+ getBlobMetadata: function(id) {},
+ log: function(str, level) {}
+ }, endpoints = {}, promises = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ contentType: null,
+ customHeaders: function(id) {
+ var params = options.getBlobMetadata(id), headers = qq.azure.util.getParamsAsHeaders(params);
+ headers["x-ms-blob-type"] = "BlockBlob";
+ return headers;
+ },
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id];
+ delete endpoints[id];
+ delete promises[id];
+ if (isError) {
+ promise.failure();
+ } else {
+ promise.success();
+ }
+ }
+ }));
+ qq.extend(this, {
+ method: method,
+ upload: function(id, xhr, url, file) {
+ var promise = new qq.Promise();
+ options.log("Submitting Put Blob request for " + id);
+ promises[id] = promise;
+ endpoints[id] = url;
+ requester.initTransport(id).withPayload(file).withHeaders({
+ "Content-Type": file.type
+ }).send(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.azure.PutBlock = function(o) {
+ "use strict";
+ var requester, method = "PUT", blockIdEntries = {}, promises = {}, options = {
+ log: function(str, level) {}
+ }, endpoints = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ contentType: null,
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id], blockIdEntry = blockIdEntries[id];
+ delete endpoints[id];
+ delete promises[id];
+ delete blockIdEntries[id];
+ if (isError) {
+ promise.failure();
+ } else {
+ promise.success(blockIdEntry);
+ }
+ }
+ }));
+ function createBlockId(partNum) {
+ var digits = 5, zeros = new Array(digits + 1).join("0"), paddedPartNum = (zeros + partNum).slice(-digits);
+ return btoa(paddedPartNum);
+ }
+ qq.extend(this, {
+ method: method,
+ upload: function(id, xhr, sasUri, partNum, blob) {
+ var promise = new qq.Promise(), blockId = createBlockId(partNum);
+ promises[id] = promise;
+ options.log(qq.format("Submitting Put Block request for {} = part {}", id, partNum));
+ endpoints[id] = qq.format("{}&comp=block&blockid={}", sasUri, encodeURIComponent(blockId));
+ blockIdEntries[id] = {
+ part: partNum,
+ id: blockId
+ };
+ requester.initTransport(id).withPayload(blob).send(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.azure.PutBlockList = function(o) {
+ "use strict";
+ var requester, method = "PUT", promises = {}, options = {
+ getBlobMetadata: function(id) {},
+ log: function(str, level) {}
+ }, endpoints = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ customHeaders: function(id) {
+ var params = options.getBlobMetadata(id);
+ return qq.azure.util.getParamsAsHeaders(params);
+ },
+ contentType: "text/plain",
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onSend: function() {},
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id];
+ delete endpoints[id];
+ delete promises[id];
+ if (isError) {
+ promise.failure(xhr);
+ } else {
+ promise.success(xhr);
+ }
+ }
+ }));
+ function createRequestBody(blockIdEntries) {
+ var doc = document.implementation.createDocument(null, "BlockList", null);
+ blockIdEntries.sort(function(a, b) {
+ return a.part - b.part;
+ });
+ qq.each(blockIdEntries, function(idx, blockIdEntry) {
+ var latestEl = doc.createElement("Latest"), latestTextEl = doc.createTextNode(blockIdEntry.id);
+ latestEl.appendChild(latestTextEl);
+ qq(doc).children()[0].appendChild(latestEl);
+ });
+ return new XMLSerializer().serializeToString(doc);
+ }
+ qq.extend(this, {
+ method: method,
+ send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {
+ var promise = new qq.Promise(), blockIdsXml = createRequestBody(blockIdEntries), xhr;
+ promises[id] = promise;
+ options.log(qq.format("Submitting Put Block List request for {}", id));
+ endpoints[id] = qq.format("{}&comp=blocklist", sasUri);
+ xhr = requester.initTransport(id).withPayload(blockIdsXml).withHeaders({
+ "x-ms-blob-content-type": fileMimeType
+ }).send();
+ registerXhrCallback(xhr);
+ return promise;
+ }
+ });
+ };
+ (function() {
+ "use strict";
+ qq.azure.FineUploader = function(o) {
+ var options = {
+ failedUploadTextDisplay: {
+ mode: "custom"
+ }
+ };
+ qq.extend(options, o, true);
+ qq.FineUploader.call(this, options, "azure");
+ };
+ qq.extend(qq.azure.FineUploader.prototype, qq.azure.FineUploaderBasic.prototype);
+ qq.extend(qq.azure.FineUploader.prototype, qq.uiPublicApi);
+ qq.extend(qq.azure.FineUploader.prototype, qq.uiPrivateApi);
+ qq.extend(qq.azure.FineUploader.prototype, {});
+ })();
+})(window);
+//# sourceMappingURL=all.fine-uploader.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.js.map b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.js.map
new file mode 100644
index 000000000000..c686e73259f8
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/traditional/traditional.form.upload.handler.js","../client/js/traditional/traditional.xhr.upload.handler.js","../client/js/traditional/all-chunks-done.ajax.requester.js","../client/js/dnd.js","../client/js/uploader.api.js","../client/js/uploader.js","../client/js/templating.js","../client/js/ui.handler.events.js","../client/js/ui.handler.click.filebuttons.js","../client/js/ui.handler.click.filename.js","../client/js/ui.handler.focusin.filenameinput.js","../client/js/ui.handler.focus.filenameinput.js","../client/js/ui.handler.edit.filename.js","../client/js/third-party/crypto-js/core.js","../client/js/third-party/crypto-js/enc-base64.js","../client/js/third-party/crypto-js/hmac.js","../client/js/third-party/crypto-js/sha1.js","../client/js/third-party/crypto-js/sha256.js","../client/js/third-party/crypto-js/lib-typedarrays.js","../client/js/s3/util.js","../client/js/non-traditional-common/uploader.basic.api.js","../client/js/s3/uploader.basic.js","../client/js/s3/request-signer.js","../client/js/uploadsuccess.ajax.requester.js","../client/js/s3/multipart.initiate.ajax.requester.js","../client/js/s3/multipart.complete.ajax.requester.js","../client/js/s3/multipart.abort.ajax.requester.js","../client/js/s3/s3.xhr.upload.handler.js","../client/js/s3/s3.form.upload.handler.js","../client/js/s3/uploader.js","../client/js/azure/util.js","../client/js/azure/uploader.basic.js","../client/js/azure/azure.xhr.upload.handler.js","../client/js/azure/get-sas.js","../client/js/azure/rest/delete-blob.js","../client/js/azure/rest/put-blob.js","../client/js/azure/rest/put-block.js","../client/js/azure/rest/put-block-list.js","../client/js/azure/uploader.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","intArray","mimeString","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","testSupportsFileInputElement","supported","tempInput","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","self","disposeSupport","options","acceptFiles","focusClass","folders","hoverClass","ios8BrowserCrashWorkaround","onChange","title","buttonId","createInput","BUTTON_ID_ATTR_NAME","setMultiple","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","byUuid","byStatus","byProxyGroupId","byBatchId","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","getDataByStatus","status","statusResults","statuses","index","statusEnum","statusResultIndexes","dataIndex","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","params","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","_options","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","promiseToReturn","fileOrUrl","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","callbacks","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","toUpperCase","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","accept","validation","allowedExtensions","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","namespace","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","messages","names","validationBase","extensionsForMessage","placeholderMatch","replacement","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","shouldParamsBeInQueryString","queue","requestData","acceptHeader","validMethods","contentType","mandatedParams","allowXRequestedWithAndCacheControl","successfulResponseCodes","DELETE","PATCH","POST","PUT","GET","onSend","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","dequeue","nextId","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","optXhr","payload","url","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","setRequestHeader","responseCode","prepareToSend","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","controller","chunkingPossible","concurrentChunkingPossible","preventRetryResponse","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","responseToReport","inProgressIdx","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","formHandlerInstanceId","onloadCallbacks","detachLoadEvents","postMessageCallbackTimers","isCors","corsMessageReceiver","expungeFile","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","_parseJsonResponse","onloadCallback","_detachLoadEvent","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","chunkFiles","resumeEnabled","xhrId","ajaxRequester","_getAjaxRequester","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","requester","getMandatedParams","_method","detectSubsampling","img","iw","naturalWidth","ih","naturalHeight","ctx","width","getContext","drawImage","getImageData","detectVerticalSquash","sy","ey","py","alpha","ratio","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","d","tmpCanvas","vertSquashRatio","dw","dh","dy","tmpCtx","sx","dx","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","imgWidth","imgHeight","opt","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","el","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetAnchor","targetProtocol","targetHostname","targetPort","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","rendered","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","TAG_IDS","TAG_INFO","274","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","vals","idHex","tagsToFindIdx","tagValHex","tagValLength","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","output","chr1","chr2","chr3","enc1","enc2","enc3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","detachPasteHandler","isImage","registerPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","formEl","_form2Obj","determineNewEndpoint","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","getIframeContentJson","doc","innerHtml","contentWindow","nodeValue","createForm","responseFromMessage","multipart","addChunkingSpecificParams","allChunksDoneRequester","AllChunksDoneAjaxRequester","createReadyStateChangedHandler","onUploadOrChunkComplete","getChunksCompleteParams","isErrorUploadResponse","parseResponse","sendChunksCompleteRequest","complete","setParamsAndGetEntityToSend","setUploadHeaders","extraHeaders","toSend","promises","endpointHandler","DragAndDrop","HIDE_ZONES_EVENT_NAME","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","droppedFiles","dropZoneElements","allowMultipleItems","dropActive","uploadDroppedFiles","uploadDropZone","filesAsArray","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","parseEntryPromise","fullPath","indexOfNameInFullPath","qqPath","fileError","isDirectory","getFilesInDirectory","allEntriesRead","entriesLeft","readFailure","accumEntries","existingPromise","dirReader","createReader","readEntries","readSuccess","newEntries","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","dropError","setupDropzone","dropArea","dropZone","UploadDropZone","onEnter","stopPropagation","onLeaveNotDescendants","onDrop","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","relatedTarget","y","setupDragDrop","dropZones","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","targetEl","errorSpecifics","preventDrop","dropOutsideDisabled","dragoverShouldBeCanceled","disableDropOutside","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","isOrSetDropDisabled","isDisabled","triggerHidezonesEvent","hideZonesEvent","triggerUsingOldApi","createEvent","initEvent","CustomEvent","dispatchEvent","attachEvents","effect","elementFromPoint","clientX","clientY","uiPublicApi","_parent","_templating","addCacheToDom","clearFiles","addExtraDropzone","_dnd","removeExtraDropzone","getItemByFileId","isHiddenForever","getFileContainer","_setupDragAndDrop","_totalFilesInBatch","_filesInBatchAddedToUi","_setupClickAndEditEventHandlers","formattedFilename","updateFilename","uploadPaused","continued","uploadContinued","getId","fileContainerOrChildEl","getFileId","getDropTarget","qqDropTarget","uiPrivateApi","_removeFileItem","removeFile","_fileButtonsClickHandler","FileButtonsClickHandler","_bindFileButtonsClickEvent","_focusinEventSupported","_isEditFilenameEnabled","_filenameClickHandler","_bindFilenameClickEvent","_filenameInputFocusInHandler","_bindFilenameInputFocusInEvent","_filenameInputFocusHandler","_bindFilenameInputFocusEvent","dragAndDrop","extraDropzones","templating","defaultDropZone","getDropZone","showDropProcessing","hideDropProcessing","errorData","lvl","onDeleteFile","onRetry","onPause","onContinue","onGetName","isEditFilenamePossible","FilenameClickHandler","FilenameInputFocusHandler","_filenameEditHandler","onGetUploadStatus","onSetName","onEditingStatusChange","isEditing","qqInput","getEditInput","qqFileContainer","hideFilename","hideEditIcon","showFilename","showEditIcon","markFilenameEditable","hideRetry","setStatusText","_classes","retrying","hidePause","FilenameInputFocusInHandler","hideSpinner","resetTotalProgress","reportDirectoryPaths","qqpath","_addToList","addHandler","updateProgress","hideCancel","hideProgress","waitingForResponse","_displayFileSize","parentRetVal","completeUpload","_markFileAsSuccessful","fail","showCancel","isRetryPossible","showRetry","_controlFailureTextDisplay","newResult","showDeleteButton","_maybeUpdateThumbnail","showSpinner","allowPause","retryNumForDisplay","maxAuto","retryNote","_showCancelLink","showAutoRetryNote","autoRetryNote","resetProgress","_onSubmitDeleteSuccess","forceConfirm","_showDeleteConfirm","_sendDeleteRequest","deletingFailedText","hideDeleteButton","deletingStatusText","confirmMessage","deleteRequestArgs","showConfirm","canned","prependData","prependIndex","dontDisplay","hideScaled","prependFiles","disableCancel","_handledProxyGroup","_clearList","addFileToCache","updateThumbnail","thumbnails","generatePreview","fileSizeOnSubmit","loadedSize","sizeForDisplay","_formatProgress","uploadedSize","formatProgress","mode","responseProperty","failureReason","failedUploadTextDisplay","failUpload","enableTooltip","_showTooltip","showMessage","_setupPastePrompt","namePromptMessage","defaultVal","showPrompt","fileStatus","placeholders","waitUntilResponse","FineUploader","listElement","template","editable","tooManyFilesError","unsupportedBrowser","promptForName","maxCount","notAvailablePath","waitingPath","timeBetweenThumbs","hasDialog","showDialog","confirm","defaultValue","prompt","Templating","templateIdOrEl","containerEl","fileContainerEl","maxThumbs","waitUntilUpdate","thumbnailNotAvailable","waitingForThumbnail","renderFailure","FILE_ID_ATTR","FILE_CLASS_PREFIX","THUMBNAIL_MAX_SIZE_ATTR","THUMBNAIL_SERVER_SCALE_ATTR","HIDE_DROPZONE_ATTR","DROPZPONE_TEXT_ATTR","IN_PROGRESS_CLASS","HIDDEN_FOREVER_CLASS","fileBatch","content","createDocumentFragment","map","isCancelDisabled","generatedThumbnails","thumbnailQueueMonitorRunning","thumbGenerationQueue","thumbnailMaxSize","selectorClasses","alertDialog","dialogCancelButton","confirmDialog","dialogMessage","dialogOkButton","promptDialog","uploader","drop","list","progressBarContainer","totalProgressBarContainer","totalProgressBar","spinner","continueButton","deleteButton","statusText","editFilenameInput","editNameIcon","dropText","dropProcessing","dropProcessingSpinner","thumbnail","previewGeneration","cachedThumbnailNotAvailableImg","cachedWaitingForThumbnailImg","isEditElementsExist","isRetryElementExist","templateHtml","showThumbnails","serverScale","cacheThumbnailPlaceholders","notAvailableUrl","waitingUrl","updatedImg","displayWaitingImg","waitingImgPlacement","maybeScalePlaceholderViaCss","show","generateNewPreview","getThumbnail","qqThumbnailId","maybeSetDisplayNotAvailableImg","generateNextQueuedPreview","queuedThumbRequest","update","processUpdateQueuedPreviewRequest","processNewQueuedPreviewRequest","getCancel","getTemplateEl","getContinue","getDialog","getDelete","getDropProcessing","getEditIcon","getPause","getProgress","getRetry","getSpinner","cssClass","previewing","notAvailableImgPlacement","parseAndGetTemplate","scriptEl","scriptHtml","fileListNode","tempTemplateEl","fileListHtml","defaultButton","dropTextEl","uploaderEl","fileTemplate","prependFile","parentEl","beforeEl","optFileOrBlob","relatedThumbnailId","useCachedPreview","showWaitingImg","setProgressBarWidth","percent","bar","progressBarSelector","targetThumbnailId","cachedThumbnailId","targetThumbnail","cachedThumbnail","hideTotalProgress","cantRenderEl","prependInfo","hideForever","batch","fileEl","fileNameEl","thumb","waitingImg","currentNode","getFileList","filenameEl","isFileName","icon","isEditIcon","isEditInput","isCancel","allowContinueButton","isPause","isContinueButton","isDeleteButton","isRetry","textEl","dialog","messageEl","inputEl","cancelBtn","okBtn","closeHandler","cancelClickHandler","okClickHandler","close","showModal","UiEventHandler","s","protectedApi","eventType","attachTo","onHandled","srcElement","getFileIdFromItem","qqFileId","getDisposeSupport","inheritedInternalApi","buttonHandlers","examineEvent","buttonType","firstLetterCapButtonType","handleFilenameEdit","FilenameEditHandler","handleInputFocus","getFilenameSansExtension","filenameSansExt","getOriginalExtension","origName","handleNameUpdate","newFilenameInputEl","origExtension","registerInputBlurHandler","registerInputEnterKeyHandler","keyCode","which","focusInput","focus","CryptoJS","C","C_lib","lib","Base","F","overrides","subtype","mixIn","init","$super","instance","properties","propertyName","clone","WordArray","words","sigBytes","encoder","Hex","wordArray","thisWords","thatWords","thisSigBytes","thatSigBytes","clamp","thatByte","nBytes","C_enc","enc","hexChars","bite","hexStr","hexStrLength","Latin1","latin1Chars","fromCharCode","latin1Str","latin1StrLength","Utf8","decodeURIComponent","escape","utf8Str","unescape","BufferedBlockAlgorithm","_data","_nDataBytes","_append","_process","doFlush","dataWords","dataSigBytes","blockSize","blockSizeBytes","nBlocksReady","_minBufferSize","nWordsReady","nBytesReady","min","_doProcessBlock","processedWords","Hasher","cfg","_doReset","messageUpdate","hash","_doFinalize","_createHelper","hasher","_createHmacHelper","C_algo","HMAC","algo","Base64","_map","base64Chars","byte1","byte2","byte3","triplet","j","paddingChar","base64Str","base64StrLength","paddingIndex","bits1","bits2","_hasher","hasherBlockSize","hasherBlockSizeBytes","oKey","_oKey","iKey","_iKey","oKeyWords","iKeyWords","innerHash","hmac","W","SHA1","_hash","M","H","n","t","nBitsTotal","nBitsLeft","floor","HmacSHA1","K","isPrime","sqrtN","factor","getFractionalBits","nPrime","SHA256","f","g","h","gamma0x","gamma0","gamma1x","gamma1","ch","maj","sigma0","sigma1","t1","t2","HmacSHA256","superInit","subInit","typedArray","Int8Array","Uint8ClampedArray","Int16Array","Uint16Array","Int32Array","Uint32Array","Float32Array","Float64Array","byteOffset","byteLength","typedArrayByteLength","s3","util","ALGORITHM_PARAM_NAME","AWS_PARAM_PREFIX","CREDENTIAL_PARAM_NAME","DATE_PARAM_NAME","REDUCED_REDUNDANCY_PARAM_NAME","REDUCED_REDUNDANCY_PARAM_VALUE","SERVER_SIDE_ENCRYPTION_PARAM_NAME","SERVER_SIDE_ENCRYPTION_PARAM_VALUE","SESSION_TOKEN_PARAM_NAME","V4_ALGORITHM_PARAM_VALUE","V4_SIGNATURE_PARAM_NAME","CASE_SENSITIVE_PARAM_NAMES","UNSIGNABLE_REST_HEADER_NAMES","UNPREFIXED_PARAM_NAMES","getBucket","patterns","bucket","pattern","_getPrefixedParamName","getPolicy","policy","conditions","date","drift","clockDrift","accessKey","acl","expectedStatus","sessionToken","successRedirectUrl","getSuccessRedirectAbsoluteUrl","minFileSize","maxFileSize","reducedRedundancy","region","serverSideEncryption","signatureVersion","expiration","getPolicyExpirationDate","Content-Type","success_action_status","success_action_redirect","getV4CredentialsString","getV4PolicyDate","awsParamName","enforceSizeLimits","refreshPolicyCredentials","newSessionToken","sessionTokenFound","oldCondIdx","oldCondObj","oldCondName","oldCondVal","generateAwsParams","signPolicyCallback","awsParams","customParams","policyJson","AWSAccessKeyId","policyAndSignature","updatedAccessKey","updatedSessionToken","signature","minSize","adjustedMinSize","adjustedMaxSize","adjustedDate","getPolicyDate","getCredentialsDate","getUTCFullYear","getUTCMonth","getUTCDate","_minutesToAdd_","minutesToAdd","pad","setMinutes","getMinutes","toISOString","number","getUTCHours","getUTCMinutes","getUTCSeconds","getUTCMilliseconds","parseIframeResponse","queryString","search","etag","targetAnchorContainer","encodeQueryStringParam","percentEncoded","uriEscape","uriEscapePath","nonTraditionalBasePublicApi","setUploadSuccessParams","_uploadSuccessParamsStore","setUploadSuccessEndpoint","_uploadSuccessEndpointStore","nonTraditionalBasePrivateApi","onCompleteArgs","successEndpoint","successCustomHeaders","uploadSuccess","successMethod","uploadSuccessParams","fileParams","onSuccessFromServer","successRequestResult","_failedSuccessRequestCallbacks","onFailureFromServer","submitSuccessRequest","successAjaxRequester","UploadSuccessAjaxRequester","_getEndpointSpecificParams","sendSuccessRequest","successRequestCallback","objectProperties","host","credentials","secretKey","iframeSupport","localBlankPagePath","onCredentialsExpired","setCredentials","_currentCredentials","_aclStore","_cannedKeys","_cannedBuckets","_buckets","_hosts","getKey","ignoreEmpty","setAcl","aclStore","_determineBucket","getHost","_determineHost","getKeyName","_determineKeyName","maxSizeLimit","oldParams","modifiedParams","paramName","credentialsProvider","onExpired","updateCredentials","_determineObjectPropertyValue","property","maybe","keynameLogic","onGetKeynameFailure","onGetKeynameSuccess","keyname","keynameToUse","_handleKeynameFunction","keynameFunc","successCallback","failureCallback","getResponseHeader","s3Key","s3Bucket","RequestSigner","thisSignatureRequester","pendingSignatures","expectingPolicy","signatureSpec","generateHeaders","signatureConstructor","getHeaders","Authorization","getRequestDate","getSignedHeaders","getEndOfUrl","v2","getStringToSign","contentMd5","headersStr","endOfUrl","signApiRequest","signatureEffort","headersWordArray","headersHmacSha1","headersHmacSha1Base64","signPolicy","policyStr","policyWordArray","base64Policy","policyHmacSha1","policyHmacSha1Base64","v4","getCanonicalQueryString","endOfUri","queryParamIdx","canonicalQueryString","encodedQueryParams","encodedQueryParamNames","queryStrings","nameAndVal","paramVal","forEach","encodedQueryParamName","getCanonicalRequest","getCanonicalUri","headerNames","hashedContent","getEncodedHashedPayload","onloadend","DONE","getScope","canonicalRequest","hashedRequest","scope","stringToSignTemplate","hashed","raw","signedHeaders","headerName","headersPattern","matches","dateKey","dateRegionKey","dateRegionServiceKey","signingKey","credentialPattern","credentialCondition","credential","condition","handleSignatureReceived","responseJson","pendingSignatureData","invalid","getStringToSignArtifacts","requestInfo","toSign","generateStringToSign","headerIndexesToRemove","headerIdx","toSignRaw","REQUEST_TYPE","MULTIPART_ABORT","uploadId","MULTIPART_INITIATE","MULTIPART_COMPLETE","MULTIPART_UPLOAD","partNum","Host","determineSignatureClientSide","toBeSigned","updatedHeaders","getToSign","signatureArtifacts","stringToSign","getSignature","queryParams","stringToSignRaw","constructStringToSign","artifacts","theHeaders","withUploadId","theUploadId","withContent","theContent","withContentType","theContentType","withPartNum","thePartNum","toUTCString","_artifacts_","pendingRequests","handleSuccessResponse","successIndicator","failureIndicator","parsedResponse","InitiateMultipartAjaxRequester","pendingInitiateRequests","getContentType","getSignatureAjaxRequester","handleInitiateRequestComplete","domParser","DOMParser","responseDoc","parseFromString","uploadIdElements","messageElements","CompleteMultipartAjaxRequester","pendingCompleteRequests","handleCompleteRequestComplete","bucketEls","keyEls","getCompleteRequestBody","etagEntries","implementation","createDocument","etagEntry","partEl","partNumEl","partNumTextEl","createTextNode","etagTextEl","etagEl","XMLSerializer","serializeToString","AbortMultipartAjaxRequester","handleAbortRequestComplete","errorEls","awsErrorMsg","onGetBucket","onGetHost","onGetKeyName","combine","etagMap","etags","requesters","completeMultipart","initHeaders","urlSafe","restSignature","put","domain","track","setup","uploadIdPromise","initiateMultipart","abortMultipart","policySignature","initParams","cachedBucket","cachedHost","shouldReset","keyName","encodedKey","parsedErrorProps","parseError","awsResponseXml","parsedDoc","errorDetails","codeEls","messageEls","existedInLocalStorage","baseStorageId","bucketName","isValidResponse","responseData","handleFinishedUpload","handleUpload","azure","AZURE_PARAM_PREFIX","_paramNameMatchesAzureParameter","getParamsAsHeaders","parseAzureError","errorTag","codeTag","messageTag","blobProperties","_cannedBlobNames","getBlobName","onGetBlobName","_determineBlobName","deleteBlob","_deleteBlob","blobNameOptionValue","fileExtension","blobNameToUse","blobName","relatedToCancel","deleteBlobSasUri","blobUriStore","deleteFileEndpointStore","getSasSuccess","sasUri","getSasFailure","DeleteBlob","getSas","GetSas","restRequestVerb","minFileSizeForChunking","getBlobMetadata","putBlob","PutBlob","putBlock","PutBlock","putBlockList","PutBlockList","getSasForPutBlobOrBlock","combineChunks","getSignedUrl","mimeType","blockIdEntries","determineBlobUrl","containerUrl","getBlobNameSuccess","getBlobNameFailure","getSasId","getSasXhr","determineBlobUrlSuccess","blobUrl","determineBlobUrlFailure","azureError","blockIdEntry","chunkingData","maybePossible","requestPromises","sasResponseReceived","blobUri","requestPromise","restVerb","bloburi","codes","endpoints","createBlockId","digits","zeros","paddedPartNum","btoa","blockId","createRequestBody","latestEl","latestTextEl","fileMimeType","registerXhrCallback","blockIdsXml","x-ms-blob-content-type"],"mappings":"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","file":"all.fine-uploader.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\" \"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq*/\n/**\n * Upload handler used that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to\n * a generic server.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.traditional = qq.traditional || {};\nqq.traditional.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log;\n\n /**\n * Returns json object received by iframe from server.\n */\n function getIframeContentJson(id, iframe) {\n /*jshint evil: true*/\n\n var response, doc, innerHtml;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n log(\"converting iframe's innerHTML to JSON\");\n log(\"innerHTML = \" + innerHtml);\n //plain text response may be wrapped in tag\n if (innerHtml && innerHtml.match(/^ 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.firefox()) {\n return !e.relatedTarget;\n }\n\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n e.preventDefault();\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n // dt.types.contains check is for firefox\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains(\"Files\")));\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n};\n","/*globals qq */\n/**\n * Defines the public API for FineUploader mode.\n */\n(function() {\n \"use strict\";\n\n qq.uiPublicApi = {\n addInitialFiles: function(cannedFileList) {\n this._parent.prototype.addInitialFiles.apply(this, arguments);\n this._templating.addCacheToDom();\n },\n\n clearStoredFiles: function() {\n this._parent.prototype.clearStoredFiles.apply(this, arguments);\n this._templating.clearFiles();\n },\n\n addExtraDropzone: function(element) {\n this._dnd && this._dnd.setupExtraDropzone(element);\n },\n\n removeExtraDropzone: function(element) {\n if (this._dnd) {\n return this._dnd.removeDropzone(element);\n }\n },\n\n getItemByFileId: function(id) {\n if (!this._templating.isHiddenForever(id)) {\n return this._templating.getFileContainer(id);\n }\n },\n\n reset: function() {\n this._parent.prototype.reset.apply(this, arguments);\n this._templating.reset();\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n if (this._dnd) {\n this._dnd.dispose();\n this._dnd = this._setupDragAndDrop();\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n\n this._setupClickAndEditEventHandlers();\n },\n\n setName: function(id, newName) {\n var formattedFilename = this._options.formatFileName(newName);\n\n this._parent.prototype.setName.apply(this, arguments);\n this._templating.updateFilename(id, formattedFilename);\n },\n\n pauseUpload: function(id) {\n var paused = this._parent.prototype.pauseUpload.apply(this, arguments);\n\n paused && this._templating.uploadPaused(id);\n return paused;\n },\n\n continueUpload: function(id) {\n var continued = this._parent.prototype.continueUpload.apply(this, arguments);\n\n continued && this._templating.uploadContinued(id);\n return continued;\n },\n\n getId: function(fileContainerOrChildEl) {\n return this._templating.getFileId(fileContainerOrChildEl);\n },\n\n getDropTarget: function(fileId) {\n var file = this.getFile(fileId);\n\n return file.qqDropTarget;\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploader mode.\n */\n qq.uiPrivateApi = {\n _getButton: function(buttonId) {\n var button = this._parent.prototype._getButton.apply(this, arguments);\n\n if (!button) {\n if (buttonId === this._defaultButtonId) {\n button = this._templating.getButton();\n }\n }\n\n return button;\n },\n\n _removeFileItem: function(fileId) {\n this._templating.removeFile(fileId);\n },\n\n _setupClickAndEditEventHandlers: function() {\n this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();\n\n // A better approach would be to check specifically for focusin event support by querying the DOM API,\n // but the DOMFocusIn event is not exposed as a property, so we have to resort to UA string sniffing.\n this._focusinEventSupported = !qq.firefox();\n\n if (this._isEditFilenameEnabled())\n {\n this._filenameClickHandler = this._bindFilenameClickEvent();\n this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();\n this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();\n }\n },\n\n _setupDragAndDrop: function() {\n var self = this,\n dropZoneElements = this._options.dragAndDrop.extraDropzones,\n templating = this._templating,\n defaultDropZone = templating.getDropZone();\n\n defaultDropZone && dropZoneElements.push(defaultDropZone);\n\n return new qq.DragAndDrop({\n dropZoneElements: dropZoneElements,\n allowMultipleItems: this._options.multiple,\n classes: {\n dropActive: this._options.classes.dropActive\n },\n callbacks: {\n processingDroppedFiles: function() {\n templating.showDropProcessing();\n },\n processingDroppedFilesComplete: function(files, targetEl) {\n templating.hideDropProcessing();\n\n qq.each(files, function(idx, file) {\n file.qqDropTarget = targetEl;\n });\n\n if (files.length) {\n self.addFiles(files, null, null);\n }\n },\n dropError: function(code, errorData) {\n self._itemError(code, errorData);\n },\n dropLog: function(message, level) {\n self.log(message, level);\n }\n }\n });\n },\n\n _bindFileButtonsClickEvent: function() {\n var self = this;\n\n return new qq.FileButtonsClickHandler({\n templating: this._templating,\n\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n\n onDeleteFile: function(fileId) {\n self.deleteFile(fileId);\n },\n\n onCancel: function(fileId) {\n self.cancel(fileId);\n },\n\n onRetry: function(fileId) {\n self.retry(fileId);\n },\n\n onPause: function(fileId) {\n self.pauseUpload(fileId);\n },\n\n onContinue: function(fileId) {\n self.continueUpload(fileId);\n },\n\n onGetName: function(fileId) {\n return self.getName(fileId);\n }\n });\n },\n\n _isEditFilenameEnabled: function() {\n /*jshint -W014 */\n return this._templating.isEditFilenamePossible()\n && !this._options.autoUpload\n && qq.FilenameClickHandler\n && qq.FilenameInputFocusHandler\n && qq.FilenameInputFocusHandler;\n },\n\n _filenameEditHandler: function() {\n var self = this,\n templating = this._templating;\n\n return {\n templating: templating,\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n onGetUploadStatus: function(fileId) {\n return self.getUploads({id: fileId}).status;\n },\n onGetName: function(fileId) {\n return self.getName(fileId);\n },\n onSetName: function(id, newName) {\n self.setName(id, newName);\n },\n onEditingStatusChange: function(id, isEditing) {\n var qqInput = qq(templating.getEditInput(id)),\n qqFileContainer = qq(templating.getFileContainer(id));\n\n if (isEditing) {\n qqInput.addClass(\"qq-editing\");\n templating.hideFilename(id);\n templating.hideEditIcon(id);\n }\n else {\n qqInput.removeClass(\"qq-editing\");\n templating.showFilename(id);\n templating.showEditIcon(id);\n }\n\n // Force IE8 and older to repaint\n qqFileContainer.addClass(\"qq-temp\").removeClass(\"qq-temp\");\n }\n };\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n this._parent.prototype._onUploadStatusChange.apply(this, arguments);\n\n if (this._isEditFilenameEnabled()) {\n // Status for a file exists before it has been added to the DOM, so we must be careful here.\n if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {\n this._templating.markFilenameEditable(id);\n this._templating.hideEditIcon(id);\n }\n }\n\n if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {\n this._templating.hideRetry(id);\n this._templating.setStatusText(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);\n }\n else if (newStatus === qq.status.UPLOAD_FAILED) {\n this._templating.hidePause(id);\n }\n },\n\n _bindFilenameInputFocusInEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusInHandler(spec);\n },\n\n _bindFilenameInputFocusEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusHandler(spec);\n },\n\n _bindFilenameClickEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameClickHandler(spec);\n },\n\n _storeForLater: function(id) {\n this._parent.prototype._storeForLater.apply(this, arguments);\n this._templating.hideSpinner(id);\n },\n\n _onAllComplete: function(successful, failed) {\n this._parent.prototype._onAllComplete.apply(this, arguments);\n this._templating.resetTotalProgress();\n },\n\n _onSubmit: function(id, name) {\n var file = this.getFile(id);\n\n if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {\n this._paramsStore.addReadOnly(id, {\n qqpath: file.qqPath\n });\n }\n\n this._parent.prototype._onSubmit.apply(this, arguments);\n this._addToList(id, name);\n },\n\n // The file item has been added to the DOM.\n _onSubmitted: function(id) {\n // If the edit filename feature is enabled, mark the filename element as \"editable\" and the associated edit icon\n if (this._isEditFilenameEnabled()) {\n this._templating.markFilenameEditable(id);\n this._templating.showEditIcon(id);\n\n // If the focusin event is not supported, we must add a focus handler to the newly create edit filename text input\n if (!this._focusinEventSupported) {\n this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));\n }\n }\n },\n\n // Update the progress bar & percentage as the file is uploaded\n _onProgress: function(id, name, loaded, total) {\n this._parent.prototype._onProgress.apply(this, arguments);\n\n this._templating.updateProgress(id, loaded, total);\n\n if (total === 0 || Math.round(loaded / total * 100) === 100) {\n this._templating.hideCancel(id);\n this._templating.hidePause(id);\n this._templating.hideProgress(id);\n this._templating.setStatusText(id, this._options.text.waitingForResponse);\n\n // If ~last byte was sent, display total file size\n this._displayFileSize(id);\n }\n else {\n // If still uploading, display percentage - total size is actually the total request(s) size\n this._displayFileSize(id, loaded, total);\n }\n },\n\n _onTotalProgress: function(loaded, total) {\n this._parent.prototype._onTotalProgress.apply(this, arguments);\n this._templating.updateTotalProgress(loaded, total);\n },\n\n _onComplete: function(id, name, result, xhr) {\n var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments),\n templating = this._templating,\n fileContainer = templating.getFileContainer(id),\n self = this;\n\n function completeUpload(result) {\n // If this file is not represented in the templating module, perhaps it was hidden intentionally.\n // If so, don't perform any UI-related tasks related to this file.\n if (!fileContainer) {\n return;\n }\n\n templating.setStatusText(id);\n\n qq(fileContainer).removeClass(self._classes.retrying);\n templating.hideProgress(id);\n\n if (self.getUploads({id: id}).status !== qq.status.UPLOAD_FAILED) {\n templating.hideCancel(id);\n }\n templating.hideSpinner(id);\n\n if (result.success) {\n self._markFileAsSuccessful(id);\n }\n else {\n qq(fileContainer).addClass(self._classes.fail);\n templating.showCancel(id);\n\n if (templating.isRetryPossible() && !self._preventRetries[id]) {\n qq(fileContainer).addClass(self._classes.retryable);\n templating.showRetry(id);\n }\n self._controlFailureTextDisplay(id, result);\n }\n }\n\n // The parent may need to perform some async operation before we can accurately determine the status of the upload.\n if (parentRetVal instanceof qq.Promise) {\n parentRetVal.done(function(newResult) {\n completeUpload(newResult);\n });\n\n }\n else {\n completeUpload(result);\n }\n\n return parentRetVal;\n },\n\n _markFileAsSuccessful: function(id) {\n var templating = this._templating;\n\n if (this._isDeletePossible()) {\n templating.showDeleteButton(id);\n }\n\n qq(templating.getFileContainer(id)).addClass(this._classes.success);\n\n this._maybeUpdateThumbnail(id);\n },\n\n _onUploadPrep: function(id) {\n this._parent.prototype._onUploadPrep.apply(this, arguments);\n this._templating.showSpinner(id);\n },\n\n _onUpload: function(id, name) {\n var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);\n\n this._templating.showSpinner(id);\n\n return parentRetVal;\n },\n\n _onUploadChunk: function(id, chunkData) {\n this._parent.prototype._onUploadChunk.apply(this, arguments);\n\n // Only display the pause button if we have finished uploading at least one chunk\n // & this file can be resumed\n if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {\n this._templating.allowPause(id);\n }\n },\n\n _onCancel: function(id, name) {\n this._parent.prototype._onCancel.apply(this, arguments);\n this._removeFileItem(id);\n\n if (this._getNotFinished() === 0) {\n this._templating.resetTotalProgress();\n }\n },\n\n _onBeforeAutoRetry: function(id) {\n var retryNumForDisplay, maxAuto, retryNote;\n\n this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);\n\n this._showCancelLink(id);\n\n if (this._options.retry.showAutoRetryNote) {\n retryNumForDisplay = this._autoRetries[id];\n maxAuto = this._options.retry.maxAutoAttempts;\n\n retryNote = this._options.retry.autoRetryNote.replace(/\\{retryNum\\}/g, retryNumForDisplay);\n retryNote = retryNote.replace(/\\{maxAuto\\}/g, maxAuto);\n\n this._templating.setStatusText(id, retryNote);\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);\n }\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {\n this._templating.resetProgress(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);\n this._templating.setStatusText(id);\n this._templating.showSpinner(id);\n this._showCancelLink(id);\n return true;\n }\n else {\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);\n this._templating.showRetry(id);\n return false;\n }\n },\n\n _onSubmitDelete: function(id) {\n var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);\n\n this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);\n },\n\n _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {\n if (this._options.deleteFile.forceConfirm) {\n this._showDeleteConfirm.apply(this, arguments);\n }\n else {\n this._sendDeleteRequest.apply(this, arguments);\n }\n },\n\n _onDeleteComplete: function(id, xhr, isError) {\n this._parent.prototype._onDeleteComplete.apply(this, arguments);\n\n this._templating.hideSpinner(id);\n\n if (isError) {\n this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);\n this._templating.showDeleteButton(id);\n }\n else {\n this._removeFileItem(id);\n }\n },\n\n _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {\n this._templating.hideDeleteButton(id);\n this._templating.showSpinner(id);\n this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);\n this._deleteHandler.sendDelete.apply(this, arguments);\n },\n\n _showDeleteConfirm: function(id, uuid, mandatedParams) {\n /*jshint -W004 */\n var fileName = this.getName(id),\n confirmMessage = this._options.deleteFile.confirmMessage.replace(/\\{filename\\}/g, fileName),\n uuid = this.getUuid(id),\n deleteRequestArgs = arguments,\n self = this,\n retVal;\n\n retVal = this._options.showConfirm(confirmMessage);\n\n if (qq.isGenericPromise(retVal)) {\n retVal.then(function() {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n });\n }\n else if (retVal !== false) {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n }\n },\n\n _addToList: function(id, name, canned) {\n var prependData,\n prependIndex = 0,\n dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled,\n record;\n\n if (this._options.display.prependFiles) {\n if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {\n prependIndex = this._filesInBatchAddedToUi - 1;\n }\n\n prependData = {\n index: prependIndex\n };\n }\n\n if (!canned) {\n if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {\n this._templating.disableCancel();\n }\n\n // Cancel all existing (previous) files and clear the list if this file is not part of\n // a scaled file group that has already been accepted, or if this file is not part of\n // a scaled file group at all.\n if (!this._options.multiple) {\n record = this.getUploads({id: id});\n\n this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;\n\n if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {\n this._handler.cancelAll();\n this._clearList();\n this._handledProxyGroup = null;\n }\n }\n }\n\n if (canned) {\n this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);\n }\n else {\n this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);\n }\n\n this._filesInBatchAddedToUi += 1;\n\n if (canned ||\n (this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading)) {\n\n this._displayFileSize(id);\n }\n },\n\n _clearList: function() {\n this._templating.clearFiles();\n this.clearStoredFiles();\n },\n\n _displayFileSize: function(id, loadedSize, totalSize) {\n var size = this.getSize(id),\n sizeForDisplay = this._formatSize(size);\n\n if (size >= 0) {\n if (loadedSize !== undefined && totalSize !== undefined) {\n sizeForDisplay = this._formatProgress(loadedSize, totalSize);\n }\n\n this._templating.updateSize(id, sizeForDisplay);\n }\n },\n\n _formatProgress: function(uploadedSize, totalSize) {\n var message = this._options.text.formatProgress;\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n r(\"{percent}\", Math.round(uploadedSize / totalSize * 100));\n r(\"{total_size}\", this._formatSize(totalSize));\n return message;\n },\n\n _controlFailureTextDisplay: function(id, response) {\n var mode, responseProperty, failureReason;\n\n mode = this._options.failedUploadTextDisplay.mode;\n responseProperty = this._options.failedUploadTextDisplay.responseProperty;\n\n if (mode === \"custom\") {\n failureReason = response[responseProperty];\n if (!failureReason) {\n failureReason = this._options.text.failUpload;\n }\n\n this._templating.setStatusText(id, failureReason);\n\n if (this._options.failedUploadTextDisplay.enableTooltip) {\n this._showTooltip(id, failureReason);\n }\n }\n else if (mode === \"default\") {\n this._templating.setStatusText(id, this._options.text.failUpload);\n }\n else if (mode !== \"none\") {\n this.log(\"failedUploadTextDisplay.mode value of '\" + mode + \"' is not valid\", \"warn\");\n }\n },\n\n _showTooltip: function(id, text) {\n this._templating.getFileContainer(id).title = text;\n },\n\n _showCancelLink: function(id) {\n if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {\n this._templating.showCancel(id);\n }\n },\n\n _itemError: function(code, name, item) {\n var message = this._parent.prototype._itemError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _batchError: function(message) {\n this._parent.prototype._batchError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _setupPastePrompt: function() {\n var self = this;\n\n this._options.callbacks.onPasteReceived = function() {\n var message = self._options.paste.namePromptMessage,\n defaultVal = self._options.paste.defaultName;\n\n return self._options.showPrompt(message, defaultVal);\n };\n },\n\n _fileOrBlobRejected: function(id, name) {\n this._totalFilesInBatch -= 1;\n this._parent.prototype._fileOrBlobRejected.apply(this, arguments);\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n this._totalFilesInBatch = items.length;\n this._filesInBatchAddedToUi = 0;\n this._parent.prototype._prepareItemsForUpload.apply(this, arguments);\n },\n\n _maybeUpdateThumbnail: function(fileId) {\n var thumbnailUrl = this._thumbnailUrls[fileId],\n fileStatus = this.getUploads({id: fileId}).status;\n\n if (fileStatus !== qq.status.DELETED &&\n (thumbnailUrl ||\n this._options.thumbnails.placeholders.waitUntilResponse ||\n !qq.supportedFeatures.imagePreviews)) {\n\n // This will replace the \"waiting\" placeholder with a \"preview not available\" placeholder\n // if called with a null thumbnailUrl.\n this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id = this._parent.prototype._addCannedFile.apply(this, arguments);\n\n this._addToList(id, this.getName(id), true);\n this._templating.hideSpinner(id);\n this._templating.hideCancel(id);\n this._markFileAsSuccessful(id);\n\n return id;\n },\n\n _setSize: function(id, newSize) {\n this._parent.prototype._setSize.apply(this, arguments);\n\n this._templating.updateSize(id, this._formatSize(newSize));\n },\n\n _sessionRequestComplete: function() {\n this._templating.addCacheToDom();\n this._parent.prototype._sessionRequestComplete.apply(this, arguments);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploader mode, which is a default UI w/ drag & drop uploading.\n */\nqq.FineUploader = function(o, namespace) {\n \"use strict\";\n\n var self = this;\n\n // By default this should inherit instance data from FineUploaderBasic, but this can be overridden\n // if the (internal) caller defines a different parent. The parent is also used by\n // the private and public API functions that need to delegate to a parent function.\n this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;\n this._parent.apply(this, arguments);\n\n // Options provided by FineUploader mode\n qq.extend(this._options, {\n element: null,\n\n button: null,\n\n listElement: null,\n\n dragAndDrop: {\n extraDropzones: [],\n reportDirectoryPaths: false\n },\n\n text: {\n formatProgress: \"{percent}% of {total_size}\",\n failUpload: \"Upload failed\",\n waitingForResponse: \"Processing...\",\n paused: \"Paused\"\n },\n\n template: \"qq-template\",\n\n classes: {\n retrying: \"qq-upload-retrying\",\n retryable: \"qq-upload-retryable\",\n success: \"qq-upload-success\",\n fail: \"qq-upload-fail\",\n editable: \"qq-editable\",\n hide: \"qq-hide\",\n dropActive: \"qq-upload-drop-area-active\"\n },\n\n failedUploadTextDisplay: {\n mode: \"default\", //default, custom, or none\n responseProperty: \"error\",\n enableTooltip: true\n },\n\n messages: {\n tooManyFilesError: \"You may only drop one file\",\n unsupportedBrowser: \"Unrecoverable error - this browser does not permit file uploading of any kind.\"\n },\n\n retry: {\n showAutoRetryNote: true,\n autoRetryNote: \"Retrying {retryNum}/{maxAuto}...\"\n },\n\n deleteFile: {\n forceConfirm: false,\n confirmMessage: \"Are you sure you want to delete {filename}?\",\n deletingStatusText: \"Deleting...\",\n deletingFailedText: \"Delete failed\"\n\n },\n\n display: {\n fileSizeOnSubmit: false,\n prependFiles: false\n },\n\n paste: {\n promptForName: false,\n namePromptMessage: \"Please name this image\"\n },\n\n thumbnails: {\n customResizer: null,\n maxCount: 0,\n placeholders: {\n waitUntilResponse: false,\n notAvailablePath: null,\n waitingPath: null\n },\n timeBetweenThumbs: 750\n },\n\n scaling: {\n hideScaled: false\n },\n\n showMessage: function(message) {\n if (self._templating.hasDialog(\"alert\")) {\n return self._templating.showDialog(\"alert\", message);\n }\n else {\n setTimeout(function() {\n window.alert(message);\n }, 0);\n }\n },\n\n showConfirm: function(message) {\n if (self._templating.hasDialog(\"confirm\")) {\n return self._templating.showDialog(\"confirm\", message);\n }\n else {\n return window.confirm(message);\n }\n },\n\n showPrompt: function(message, defaultValue) {\n if (self._templating.hasDialog(\"prompt\")) {\n return self._templating.showDialog(\"prompt\", message, defaultValue);\n }\n else {\n return window.prompt(message, defaultValue);\n }\n }\n }, true);\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._templating = new qq.Templating({\n log: qq.bind(this.log, this),\n templateIdOrEl: this._options.template,\n containerEl: this._options.element,\n fileContainerEl: this._options.listElement,\n button: this._options.button,\n imageGenerator: this._imageGenerator,\n classes: {\n hide: this._options.classes.hide,\n editable: this._options.classes.editable\n },\n limits: {\n maxThumbs: this._options.thumbnails.maxCount,\n timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs\n },\n placeholders: {\n waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,\n thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,\n waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath\n },\n text: this._options.text\n });\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);\n }\n else if (!qq.supportedFeatures.uploading || (this._options.cors.expected && !qq.supportedFeatures.uploadCors)) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowser);\n }\n else {\n this._wrapCallbacks();\n\n this._templating.render();\n\n this._classes = this._options.classes;\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._setupClickAndEditEventHandlers();\n\n if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {\n this._dnd = this._setupDragAndDrop();\n }\n\n if (this._options.paste.targetElement && this._options.paste.promptForName) {\n if (qq.PasteSupport) {\n this._setupPastePrompt();\n }\n else {\n this.log(\"Paste support module not found.\", \"error\");\n }\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n }\n};\n\n// Inherit the base public & private API methods\nqq.extend(qq.FineUploader.prototype, qq.basePublicApi);\nqq.extend(qq.FineUploader.prototype, qq.basePrivateApi);\n\n// Add the FineUploader/default UI public & private UI methods, which may override some base methods.\nqq.extend(qq.FineUploader.prototype, qq.uiPublicApi);\nqq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);\n","/* globals qq */\n/* jshint -W065 */\n/**\n * Module responsible for rendering all Fine Uploader UI templates. This module also asserts at least\n * a limited amount of control over the template elements after they are added to the DOM.\n * Wherever possible, this module asserts total control over template elements present in the DOM.\n *\n * @param spec Specification object used to control various templating behaviors\n * @constructor\n */\nqq.Templating = function(spec) {\n \"use strict\";\n\n var FILE_ID_ATTR = \"qq-file-id\",\n FILE_CLASS_PREFIX = \"qq-file-id-\",\n THUMBNAIL_MAX_SIZE_ATTR = \"qq-max-size\",\n THUMBNAIL_SERVER_SCALE_ATTR = \"qq-server-scale\",\n // This variable is duplicated in the DnD module since it can function as a standalone as well\n HIDE_DROPZONE_ATTR = \"qq-hide-dropzone\",\n DROPZPONE_TEXT_ATTR = \"qq-drop-area-text\",\n IN_PROGRESS_CLASS = \"qq-in-progress\",\n HIDDEN_FOREVER_CLASS = \"qq-hidden-forever\",\n fileBatch = {\n content: document.createDocumentFragment(),\n map: {}\n },\n isCancelDisabled = false,\n generatedThumbnails = 0,\n thumbnailQueueMonitorRunning = false,\n thumbGenerationQueue = [],\n thumbnailMaxSize = -1,\n options = {\n log: null,\n limits: {\n maxThumbs: 0,\n timeBetweenThumbs: 750\n },\n templateIdOrEl: \"qq-template\",\n containerEl: null,\n fileContainerEl: null,\n button: null,\n imageGenerator: null,\n classes: {\n hide: \"qq-hide\",\n editable: \"qq-editable\"\n },\n placeholders: {\n waitUntilUpdate: false,\n thumbnailNotAvailable: null,\n waitingForThumbnail: null\n },\n text: {\n paused: \"Paused\"\n }\n },\n selectorClasses = {\n button: \"qq-upload-button-selector\",\n alertDialog: \"qq-alert-dialog-selector\",\n dialogCancelButton: \"qq-cancel-button-selector\",\n confirmDialog: \"qq-confirm-dialog-selector\",\n dialogMessage: \"qq-dialog-message-selector\",\n dialogOkButton: \"qq-ok-button-selector\",\n promptDialog: \"qq-prompt-dialog-selector\",\n uploader: \"qq-uploader-selector\",\n drop: \"qq-upload-drop-area-selector\",\n list: \"qq-upload-list-selector\",\n progressBarContainer: \"qq-progress-bar-container-selector\",\n progressBar: \"qq-progress-bar-selector\",\n totalProgressBarContainer: \"qq-total-progress-bar-container-selector\",\n totalProgressBar: \"qq-total-progress-bar-selector\",\n file: \"qq-upload-file-selector\",\n spinner: \"qq-upload-spinner-selector\",\n size: \"qq-upload-size-selector\",\n cancel: \"qq-upload-cancel-selector\",\n pause: \"qq-upload-pause-selector\",\n continueButton: \"qq-upload-continue-selector\",\n deleteButton: \"qq-upload-delete-selector\",\n retry: \"qq-upload-retry-selector\",\n statusText: \"qq-upload-status-text-selector\",\n editFilenameInput: \"qq-edit-filename-selector\",\n editNameIcon: \"qq-edit-filename-icon-selector\",\n dropText: \"qq-upload-drop-area-text-selector\",\n dropProcessing: \"qq-drop-processing-selector\",\n dropProcessingSpinner: \"qq-drop-processing-spinner-selector\",\n thumbnail: \"qq-thumbnail-selector\"\n },\n previewGeneration = {},\n cachedThumbnailNotAvailableImg = new qq.Promise(),\n cachedWaitingForThumbnailImg = new qq.Promise(),\n log,\n isEditElementsExist,\n isRetryElementExist,\n templateHtml,\n container,\n fileList,\n showThumbnails,\n serverScale,\n\n // During initialization of the templating module we should cache any\n // placeholder images so we can quickly swap them into the file list on demand.\n // Any placeholder images that cannot be loaded/found are simply ignored.\n cacheThumbnailPlaceholders = function() {\n var notAvailableUrl = options.placeholders.thumbnailNotAvailable,\n waitingUrl = options.placeholders.waitingForThumbnail,\n spec = {\n maxSize: thumbnailMaxSize,\n scale: serverScale\n };\n\n if (showThumbnails) {\n if (notAvailableUrl) {\n options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedThumbnailNotAvailableImg.success(updatedImg);\n },\n function() {\n cachedThumbnailNotAvailableImg.failure();\n log(\"Problem loading 'not available' placeholder image at \" + notAvailableUrl, \"error\");\n }\n );\n }\n else {\n cachedThumbnailNotAvailableImg.failure();\n }\n\n if (waitingUrl) {\n options.imageGenerator.generate(waitingUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedWaitingForThumbnailImg.success(updatedImg);\n },\n function() {\n cachedWaitingForThumbnailImg.failure();\n log(\"Problem loading 'waiting for thumbnail' placeholder image at \" + waitingUrl, \"error\");\n }\n );\n }\n else {\n cachedWaitingForThumbnailImg.failure();\n }\n }\n },\n\n // Displays a \"waiting for thumbnail\" type placeholder image\n // iff we were able to load it during initialization of the templating module.\n displayWaitingImg = function(thumbnail) {\n var waitingImgPlacement = new qq.Promise();\n\n cachedWaitingForThumbnailImg.then(function(img) {\n maybeScalePlaceholderViaCss(img, thumbnail);\n /* jshint eqnull:true */\n if (!thumbnail.src) {\n thumbnail.src = img.src;\n thumbnail.onload = function() {\n thumbnail.onload = null;\n show(thumbnail);\n waitingImgPlacement.success();\n };\n }\n else {\n waitingImgPlacement.success();\n }\n }, function() {\n // In some browsers (such as IE9 and older) an img w/out a src attribute\n // are displayed as \"broken\" images, so we should just hide the img tag\n // if we aren't going to display the \"waiting\" placeholder.\n hide(thumbnail);\n waitingImgPlacement.success();\n });\n\n return waitingImgPlacement;\n },\n\n generateNewPreview = function(id, blob, spec) {\n var thumbnail = getThumbnail(id);\n\n log(\"Generating new thumbnail for \" + id);\n blob.qqThumbnailId = id;\n\n return options.imageGenerator.generate(blob, thumbnail, spec).then(\n function() {\n generatedThumbnails++;\n show(thumbnail);\n previewGeneration[id].success();\n },\n function() {\n previewGeneration[id].failure();\n\n // Display the \"not available\" placeholder img only if we are\n // not expecting a thumbnail at a later point, such as in a server response.\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n }\n });\n },\n\n generateNextQueuedPreview = function() {\n if (thumbGenerationQueue.length) {\n thumbnailQueueMonitorRunning = true;\n\n var queuedThumbRequest = thumbGenerationQueue.shift();\n\n if (queuedThumbRequest.update) {\n processUpdateQueuedPreviewRequest(queuedThumbRequest);\n }\n else {\n processNewQueuedPreviewRequest(queuedThumbRequest);\n }\n }\n else {\n thumbnailQueueMonitorRunning = false;\n }\n },\n\n getCancel = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.cancel);\n },\n\n getContinue = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.continueButton);\n },\n\n getDialog = function(type) {\n return getTemplateEl(container, selectorClasses[type + \"Dialog\"]);\n },\n\n getDelete = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.deleteButton);\n },\n\n getDropProcessing = function() {\n return getTemplateEl(container, selectorClasses.dropProcessing);\n },\n\n getEditIcon = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editNameIcon);\n },\n\n getFile = function(id) {\n return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);\n },\n\n getFilename = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.file);\n },\n\n getPause = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.pause);\n },\n\n getProgress = function(id) {\n /* jshint eqnull:true */\n // Total progress bar\n if (id == null) {\n return getTemplateEl(container, selectorClasses.totalProgressBarContainer) ||\n getTemplateEl(container, selectorClasses.totalProgressBar);\n }\n\n // Per-file progress bar\n return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) ||\n getTemplateEl(getFile(id), selectorClasses.progressBar);\n },\n\n getRetry = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.retry);\n },\n\n getSize = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.size);\n },\n\n getSpinner = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.spinner);\n },\n\n getTemplateEl = function(context, cssClass) {\n return context && qq(context).getFirstByClass(cssClass);\n },\n\n getThumbnail = function(id) {\n return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);\n },\n\n hide = function(el) {\n el && qq(el).addClass(options.classes.hide);\n },\n\n // Ensures a placeholder image does not exceed any max size specified\n // via `style` attribute properties iff was not used to scale\n // the placeholder AND the target doesn't already have these `style` attribute properties set.\n maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {\n var maxWidth = placeholder.style.maxWidth,\n maxHeight = placeholder.style.maxHeight;\n\n if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {\n qq(thumbnail).css({\n maxWidth: maxWidth,\n maxHeight: maxHeight\n });\n }\n },\n\n // Displays a \"thumbnail not available\" type placeholder image\n // iff we were able to load this placeholder during initialization\n // of the templating module or after preview generation has failed.\n maybeSetDisplayNotAvailableImg = function(id, thumbnail) {\n var previewing = previewGeneration[id] || new qq.Promise().failure(),\n notAvailableImgPlacement = new qq.Promise();\n\n cachedThumbnailNotAvailableImg.then(function(img) {\n previewing.then(\n function() {\n notAvailableImgPlacement.success();\n },\n function() {\n maybeScalePlaceholderViaCss(img, thumbnail);\n\n thumbnail.onload = function() {\n thumbnail.onload = null;\n notAvailableImgPlacement.success();\n };\n\n thumbnail.src = img.src;\n show(thumbnail);\n }\n );\n });\n\n return notAvailableImgPlacement;\n },\n\n /**\n * Grabs the HTML from the script tag holding the template markup. This function will also adjust\n * some internally-tracked state variables based on the contents of the template.\n * The template is filtered so that irrelevant elements (such as the drop zone if DnD is not supported)\n * are omitted from the DOM. Useful errors will be thrown if the template cannot be parsed.\n *\n * @returns {{template: *, fileTemplate: *}} HTML for the top-level file items templates\n */\n parseAndGetTemplate = function() {\n var scriptEl,\n scriptHtml,\n fileListNode,\n tempTemplateEl,\n fileListHtml,\n defaultButton,\n dropArea,\n thumbnail,\n dropProcessing,\n dropTextEl,\n uploaderEl;\n\n log(\"Parsing template\");\n\n /*jshint -W116*/\n if (options.templateIdOrEl == null) {\n throw new Error(\"You MUST specify either a template element or ID!\");\n }\n\n // Grab the contents of the script tag holding the template.\n if (qq.isString(options.templateIdOrEl)) {\n scriptEl = document.getElementById(options.templateIdOrEl);\n\n if (scriptEl === null) {\n throw new Error(qq.format(\"Cannot find template script at ID '{}'!\", options.templateIdOrEl));\n }\n\n scriptHtml = scriptEl.innerHTML;\n }\n else {\n if (options.templateIdOrEl.innerHTML === undefined) {\n throw new Error(\"You have specified an invalid value for the template option! \" +\n \"It must be an ID or an Element.\");\n }\n\n scriptHtml = options.templateIdOrEl.innerHTML;\n }\n\n scriptHtml = qq.trimStr(scriptHtml);\n tempTemplateEl = document.createElement(\"div\");\n tempTemplateEl.appendChild(qq.toElement(scriptHtml));\n uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);\n\n // Don't include the default template button in the DOM\n // if an alternate button container has been specified.\n if (options.button) {\n defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);\n if (defaultButton) {\n qq(defaultButton).remove();\n }\n }\n\n // Omit the drop processing element from the DOM if DnD is not supported by the UA,\n // or the drag and drop module is not found.\n // NOTE: We are consciously not removing the drop zone if the UA doesn't support DnD\n // to support layouts where the drop zone is also a container for visible elements,\n // such as the file list.\n if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {\n dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);\n if (dropProcessing) {\n qq(dropProcessing).remove();\n }\n }\n\n dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);\n\n // If DnD is not available then remove\n // it from the DOM as well.\n if (dropArea && !qq.DragAndDrop) {\n log(\"DnD module unavailable.\", \"info\");\n qq(dropArea).remove();\n }\n\n if (!qq.supportedFeatures.fileDrop) {\n // don't display any \"drop files to upload\" background text\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {\n // If there is a drop area defined in the template, and the current UA doesn't support DnD,\n // and the drop area is marked as \"hide before enter\", ensure it is hidden as the DnD module\n // will not do this (since we will not be loading the DnD module)\n qq(dropArea).css({\n display: \"none\"\n });\n }\n }\n else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {\n dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);\n dropTextEl && qq(dropTextEl).remove();\n }\n\n // Ensure the `showThumbnails` flag is only set if the thumbnail element\n // is present in the template AND the current UA is capable of generating client-side previews.\n thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);\n if (!showThumbnails) {\n thumbnail && qq(thumbnail).remove();\n }\n else if (thumbnail) {\n thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));\n // Only enforce max size if the attr value is non-zero\n thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;\n\n serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);\n }\n showThumbnails = showThumbnails && thumbnail;\n\n isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;\n isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;\n\n fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);\n /*jshint -W116*/\n if (fileListNode == null) {\n throw new Error(\"Could not find the file list container in the template!\");\n }\n\n fileListHtml = fileListNode.innerHTML;\n fileListNode.innerHTML = \"\";\n\n // We must call `createElement` in IE8 in order to target and hide any via CSS\n if (tempTemplateEl.getElementsByTagName(\"DIALOG\").length) {\n document.createElement(\"dialog\");\n }\n\n log(\"Template parsing complete\");\n\n return {\n template: qq.trimStr(tempTemplateEl.innerHTML),\n fileTemplate: qq.trimStr(fileListHtml)\n };\n },\n\n prependFile = function(el, index, fileList) {\n var parentEl = fileList,\n beforeEl = parentEl.firstChild;\n\n if (index > 0) {\n beforeEl = qq(parentEl).children()[index].nextSibling;\n\n }\n\n parentEl.insertBefore(el, beforeEl);\n },\n\n processNewQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n optFileOrBlob = queuedThumbRequest.optFileOrBlob,\n relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n maxSize: thumbnailMaxSize,\n orient: true,\n scale: true\n };\n\n if (qq.supportedFeatures.imagePreviews) {\n if (thumbnail) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n displayWaitingImg(thumbnail).done(function() {\n previewGeneration[id] = new qq.Promise();\n\n previewGeneration[id].done(function() {\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n });\n\n /* jshint eqnull: true */\n // If we've already generated an for this file, use the one that exists,\n // don't waste resources generating a new one.\n if (relatedThumbnailId != null) {\n useCachedPreview(id, relatedThumbnailId);\n }\n else {\n generateNewPreview(id, optFileOrBlob, spec);\n }\n });\n }\n }\n // File element in template may have been removed, so move on to next item in queue\n else {\n generateNextQueuedPreview();\n }\n }\n else if (thumbnail) {\n displayWaitingImg(thumbnail);\n generateNextQueuedPreview();\n }\n },\n\n processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n thumbnailUrl = queuedThumbRequest.thumbnailUrl,\n showWaitingImg = queuedThumbRequest.showWaitingImg,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n scale: serverScale,\n maxSize: thumbnailMaxSize\n };\n\n if (thumbnail) {\n if (thumbnailUrl) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n if (showWaitingImg) {\n displayWaitingImg(thumbnail);\n }\n\n return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(\n function() {\n show(thumbnail);\n generatedThumbnails++;\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n },\n\n function() {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n }\n );\n }\n }\n else {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n }\n },\n\n setProgressBarWidth = function(id, percent) {\n var bar = getProgress(id),\n /* jshint eqnull:true */\n progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;\n\n if (bar && !qq(bar).hasClass(progressBarSelector)) {\n bar = qq(bar).getFirstByClass(progressBarSelector);\n }\n\n if (bar) {\n qq(bar).css({width: percent + \"%\"});\n bar.setAttribute(\"aria-valuenow\", percent);\n }\n },\n\n show = function(el) {\n el && qq(el).removeClass(options.classes.hide);\n },\n\n useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {\n var targetThumbnail = getThumbnail(targetThumbnailId),\n cachedThumbnail = getThumbnail(cachedThumbnailId);\n\n log(qq.format(\"ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.\", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));\n\n // Generation of the related thumbnail may still be in progress, so, wait until it is done.\n previewGeneration[cachedThumbnailId].then(function() {\n generatedThumbnails++;\n previewGeneration[targetThumbnailId].success();\n log(qq.format(\"Now using previously generated thumbnail created for ID {} on ID {}.\", cachedThumbnailId, targetThumbnailId));\n targetThumbnail.src = cachedThumbnail.src;\n show(targetThumbnail);\n },\n function() {\n previewGeneration[targetThumbnailId].failure();\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);\n }\n });\n };\n\n qq.extend(options, spec);\n log = options.log;\n\n // No need to worry about conserving CPU or memory on older browsers,\n // since there is no ability to preview, and thumbnail display is primitive and quick.\n if (!qq.supportedFeatures.imagePreviews) {\n options.limits.timeBetweenThumbs = 0;\n options.limits.maxThumbs = 0;\n }\n\n container = options.containerEl;\n showThumbnails = options.imageGenerator !== undefined;\n templateHtml = parseAndGetTemplate();\n\n cacheThumbnailPlaceholders();\n\n qq.extend(this, {\n render: function() {\n log(\"Rendering template in DOM.\");\n\n generatedThumbnails = 0;\n\n container.innerHTML = templateHtml.template;\n hide(getDropProcessing());\n this.hideTotalProgress();\n fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);\n\n log(\"Template rendering complete\");\n },\n\n renderFailure: function(message) {\n var cantRenderEl = qq.toElement(message);\n container.innerHTML = \"\";\n container.appendChild(cantRenderEl);\n },\n\n reset: function() {\n this.render();\n },\n\n clearFiles: function() {\n fileList.innerHTML = \"\";\n },\n\n disableCancel: function() {\n isCancelDisabled = true;\n },\n\n addFile: function(id, name, prependInfo, hideForever, batch) {\n var fileEl = qq.toElement(templateHtml.fileTemplate),\n fileNameEl = getTemplateEl(fileEl, selectorClasses.file),\n uploaderEl = getTemplateEl(container, selectorClasses.uploader),\n fileContainer = batch ? fileBatch.content : fileList,\n thumb;\n\n if (batch) {\n fileBatch.map[id] = fileEl;\n }\n\n qq(fileEl).addClass(FILE_CLASS_PREFIX + id);\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (fileNameEl) {\n qq(fileNameEl).setText(name);\n fileNameEl.setAttribute(\"title\", name);\n }\n\n fileEl.setAttribute(FILE_ID_ATTR, id);\n\n if (prependInfo) {\n prependFile(fileEl, prependInfo.index, fileContainer);\n }\n else {\n fileContainer.appendChild(fileEl);\n }\n\n if (hideForever) {\n fileEl.style.display = \"none\";\n qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);\n }\n else {\n hide(getProgress(id));\n hide(getSize(id));\n hide(getDelete(id));\n hide(getRetry(id));\n hide(getPause(id));\n hide(getContinue(id));\n\n if (isCancelDisabled) {\n this.hideCancel(id);\n }\n\n thumb = getThumbnail(id);\n if (thumb && !thumb.src) {\n cachedWaitingForThumbnailImg.then(function(waitingImg) {\n thumb.src = waitingImg.src;\n if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {\n qq(thumb).css({\n maxHeight: waitingImg.style.maxHeight,\n maxWidth: waitingImg.style.maxWidth\n });\n }\n\n show(thumb);\n });\n }\n }\n },\n\n addFileToCache: function(id, name, prependInfo, hideForever) {\n this.addFile(id, name, prependInfo, hideForever, true);\n },\n\n addCacheToDom: function() {\n fileList.appendChild(fileBatch.content);\n fileBatch.content = document.createDocumentFragment();\n fileBatch.map = {};\n },\n\n removeFile: function(id) {\n qq(getFile(id)).remove();\n },\n\n getFileId: function(el) {\n var currentNode = el;\n\n if (currentNode) {\n /*jshint -W116*/\n while (currentNode.getAttribute(FILE_ID_ATTR) == null) {\n currentNode = currentNode.parentNode;\n }\n\n return parseInt(currentNode.getAttribute(FILE_ID_ATTR));\n }\n },\n\n getFileList: function() {\n return fileList;\n },\n\n markFilenameEditable: function(id) {\n var filename = getFilename(id);\n\n filename && qq(filename).addClass(options.classes.editable);\n },\n\n updateFilename: function(id, name) {\n var filenameEl = getFilename(id);\n\n if (filenameEl) {\n qq(filenameEl).setText(name);\n filenameEl.setAttribute(\"title\", name);\n }\n },\n\n hideFilename: function(id) {\n hide(getFilename(id));\n },\n\n showFilename: function(id) {\n show(getFilename(id));\n },\n\n isFileName: function(el) {\n return qq(el).hasClass(selectorClasses.file);\n },\n\n getButton: function() {\n return options.button || getTemplateEl(container, selectorClasses.button);\n },\n\n hideDropProcessing: function() {\n hide(getDropProcessing());\n },\n\n showDropProcessing: function() {\n show(getDropProcessing());\n },\n\n getDropZone: function() {\n return getTemplateEl(container, selectorClasses.drop);\n },\n\n isEditFilenamePossible: function() {\n return isEditElementsExist;\n },\n\n hideRetry: function(id) {\n hide(getRetry(id));\n },\n\n isRetryPossible: function() {\n return isRetryElementExist;\n },\n\n showRetry: function(id) {\n show(getRetry(id));\n },\n\n getFileContainer: function(id) {\n return getFile(id);\n },\n\n showEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).addClass(options.classes.editable);\n },\n\n isHiddenForever: function(id) {\n return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);\n },\n\n hideEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).removeClass(options.classes.editable);\n },\n\n isEditIcon: function(el) {\n return qq(el).hasClass(selectorClasses.editNameIcon, true);\n },\n\n getEditInput: function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);\n },\n\n isEditInput: function(el) {\n return qq(el).hasClass(selectorClasses.editFilenameInput, true);\n },\n\n updateProgress: function(id, loaded, total) {\n var bar = getProgress(id),\n percent;\n\n if (bar && total > 0) {\n percent = Math.round(loaded / total * 100);\n\n if (percent === 100) {\n hide(bar);\n }\n else {\n show(bar);\n }\n\n setProgressBarWidth(id, percent);\n }\n },\n\n updateTotalProgress: function(loaded, total) {\n this.updateProgress(null, loaded, total);\n },\n\n hideProgress: function(id) {\n var bar = getProgress(id);\n\n bar && hide(bar);\n },\n\n hideTotalProgress: function() {\n this.hideProgress();\n },\n\n resetProgress: function(id) {\n setProgressBarWidth(id, 0);\n this.hideTotalProgress(id);\n },\n\n resetTotalProgress: function() {\n this.resetProgress();\n },\n\n showCancel: function(id) {\n if (!isCancelDisabled) {\n var cancel = getCancel(id);\n\n cancel && qq(cancel).removeClass(options.classes.hide);\n }\n },\n\n hideCancel: function(id) {\n hide(getCancel(id));\n },\n\n isCancel: function(el) {\n return qq(el).hasClass(selectorClasses.cancel, true);\n },\n\n allowPause: function(id) {\n show(getPause(id));\n hide(getContinue(id));\n },\n\n uploadPaused: function(id) {\n this.setStatusText(id, options.text.paused);\n this.allowContinueButton(id);\n hide(getSpinner(id));\n },\n\n hidePause: function(id) {\n hide(getPause(id));\n },\n\n isPause: function(el) {\n return qq(el).hasClass(selectorClasses.pause, true);\n },\n\n isContinueButton: function(el) {\n return qq(el).hasClass(selectorClasses.continueButton, true);\n },\n\n allowContinueButton: function(id) {\n show(getContinue(id));\n hide(getPause(id));\n },\n\n uploadContinued: function(id) {\n this.setStatusText(id, \"\");\n this.allowPause(id);\n show(getSpinner(id));\n },\n\n showDeleteButton: function(id) {\n show(getDelete(id));\n },\n\n hideDeleteButton: function(id) {\n hide(getDelete(id));\n },\n\n isDeleteButton: function(el) {\n return qq(el).hasClass(selectorClasses.deleteButton, true);\n },\n\n isRetry: function(el) {\n return qq(el).hasClass(selectorClasses.retry, true);\n },\n\n updateSize: function(id, text) {\n var size = getSize(id);\n\n if (size) {\n show(size);\n qq(size).setText(text);\n }\n },\n\n setStatusText: function(id, text) {\n var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);\n\n if (textEl) {\n /*jshint -W116*/\n if (text == null) {\n qq(textEl).clearText();\n }\n else {\n qq(textEl).setText(text);\n }\n }\n },\n\n hideSpinner: function(id) {\n qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);\n hide(getSpinner(id));\n },\n\n showSpinner: function(id) {\n qq(getFile(id)).addClass(IN_PROGRESS_CLASS);\n show(getSpinner(id));\n },\n\n generatePreview: function(id, optFileOrBlob, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({id: id, customResizeFunction: customResizeFunction, optFileOrBlob: optFileOrBlob});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({customResizeFunction: customResizeFunction, update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n hasDialog: function(type) {\n return qq.supportedFeatures.dialogElement && !!getDialog(type);\n },\n\n showDialog: function(type, message, defaultValue) {\n var dialog = getDialog(type),\n messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage),\n inputEl = dialog.getElementsByTagName(\"INPUT\")[0],\n cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton),\n okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton),\n promise = new qq.Promise(),\n\n closeHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.removeEventListener(\"click\", okClickHandler);\n promise.failure();\n },\n\n cancelClickHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n dialog.close();\n },\n\n okClickHandler = function() {\n dialog.removeEventListener(\"close\", closeHandler);\n okBtn.removeEventListener(\"click\", okClickHandler);\n dialog.close();\n\n promise.success(inputEl && inputEl.value);\n };\n\n dialog.addEventListener(\"close\", closeHandler);\n cancelBtn.addEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.addEventListener(\"click\", okClickHandler);\n\n if (inputEl) {\n inputEl.value = defaultValue;\n }\n messageEl.textContent = message;\n\n dialog.showModal();\n\n return promise;\n }\n });\n};\n","/*globals qq */\n// Base handler for UI (FineUploader mode) events.\n// Some more specific handlers inherit from this one.\nqq.UiEventHandler = function(s, protectedApi) {\n \"use strict\";\n\n var disposer = new qq.DisposeSupport(),\n spec = {\n eventType: \"click\",\n attachTo: null,\n onHandled: function(target, event) {}\n };\n\n // This makes up the \"public\" API methods that will be accessible\n // to instances constructing a base or child handler\n qq.extend(this, {\n addHandler: function(element) {\n addHandler(element);\n },\n\n dispose: function() {\n disposer.dispose();\n }\n });\n\n function addHandler(element) {\n disposer.attach(element, spec.eventType, function(event) {\n // Only in IE: the `event` is a property of the `window`.\n event = event || window.event;\n\n // On older browsers, we must check the `srcElement` instead of the `target`.\n var target = event.target || event.srcElement;\n\n spec.onHandled(target, event);\n });\n }\n\n // These make up the \"protected\" API methods that children of this base handler will utilize.\n qq.extend(protectedApi, {\n getFileIdFromItem: function(item) {\n return item.qqFileId;\n },\n\n getDisposeSupport: function() {\n return disposer;\n }\n });\n\n qq.extend(spec, s);\n\n if (spec.attachTo) {\n addHandler(spec.attachTo);\n }\n};\n","/* global qq */\nqq.FileButtonsClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n onDeleteFile: function(fileId) {},\n onCancel: function(fileId) {},\n onRetry: function(fileId) {},\n onPause: function(fileId) {},\n onContinue: function(fileId) {},\n onGetName: function(fileId) {}\n },\n buttonHandlers = {\n cancel: function(id) { spec.onCancel(id); },\n retry: function(id) { spec.onRetry(id); },\n deleteButton: function(id) { spec.onDeleteFile(id); },\n pause: function(id) { spec.onPause(id); },\n continueButton: function(id) { spec.onContinue(id); }\n };\n\n function examineEvent(target, event) {\n qq.each(buttonHandlers, function(buttonType, handler) {\n var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1),\n fileId;\n\n if (spec.templating[\"is\" + firstLetterCapButtonType](target)) {\n fileId = spec.templating.getFileId(target);\n qq.preventDefault(event);\n spec.log(qq.format(\"Detected valid file button click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n handler(fileId);\n return false;\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect click events on filename display elements.\nqq.FilenameClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n classes: {\n file: \"qq-upload-file\",\n editNameIcon: \"qq-edit-filename-icon\"\n },\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {}\n };\n\n qq.extend(spec, s);\n\n // This will be called by the parent handler when a `click` event is received on the list element.\n function examineEvent(target, event) {\n if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n // We only allow users to change filenames of files that have been submitted but not yet uploaded.\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n qq.preventDefault(event);\n\n inheritedInternalApi.handleFilenameEdit(fileId, target, true);\n }\n }\n }\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect focusin events on file edit input elements.\nqq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n onGetUploadStatus: function(fileId) {},\n log: function(message, lvl) {}\n };\n\n if (!inheritedInternalApi) {\n inheritedInternalApi = {};\n }\n\n // This will be called by the parent handler when a `focusin` event is received on the list element.\n function handleInputFocus(target, event) {\n if (spec.templating.isEditInput(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename input focus event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n inheritedInternalApi.handleFilenameEdit(fileId, target);\n }\n }\n }\n\n spec.eventType = \"focusin\";\n spec.onHandled = handleInputFocus;\n\n qq.extend(spec, s);\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n/**\n * Child of FilenameInputFocusInHandler. Used to detect focus events on file edit input elements. This child module is only\n * needed for UAs that do not support the focusin event. Currently, only Firefox lacks this event.\n *\n * @param spec Overrides for default specifications\n */\nqq.FilenameInputFocusHandler = function(spec) {\n \"use strict\";\n\n spec.eventType = \"focus\";\n spec.attachTo = null;\n\n qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));\n};\n","/*globals qq */\n// Handles edit-related events on a file item (FineUploader mode). This is meant to be a parent handler.\n// Children will delegate to this handler when specific edit-related actions are detected.\nqq.FilenameEditHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n log: function(message, lvl) {},\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {},\n onSetName: function(fileId, newName) {},\n onEditingStatusChange: function(fileId, isEditing) {}\n };\n\n function getFilenameSansExtension(fileId) {\n var filenameSansExt = spec.onGetName(fileId),\n extIdx = filenameSansExt.lastIndexOf(\".\");\n\n if (extIdx > 0) {\n filenameSansExt = filenameSansExt.substr(0, extIdx);\n }\n\n return filenameSansExt;\n }\n\n function getOriginalExtension(fileId) {\n var origName = spec.onGetName(fileId);\n return qq.getExtension(origName);\n }\n\n // Callback iff the name has been changed\n function handleNameUpdate(newFilenameInputEl, fileId) {\n var newName = newFilenameInputEl.value,\n origExtension;\n\n if (newName !== undefined && qq.trimStr(newName).length > 0) {\n origExtension = getOriginalExtension(fileId);\n\n if (origExtension !== undefined) {\n newName = newName + \".\" + origExtension;\n }\n\n spec.onSetName(fileId, newName);\n }\n\n spec.onEditingStatusChange(fileId, false);\n }\n\n // The name has been updated if the filename edit input loses focus.\n function registerInputBlurHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"blur\", function() {\n handleNameUpdate(inputEl, fileId);\n });\n }\n\n // The name has been updated if the user presses enter.\n function registerInputEnterKeyHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"keyup\", function(event) {\n\n var code = event.keyCode || event.which;\n\n if (code === 13) {\n handleNameUpdate(inputEl, fileId);\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n\n qq.extend(inheritedInternalApi, {\n handleFilenameEdit: function(id, target, focusInput) {\n var newFilenameInputEl = spec.templating.getEditInput(id);\n\n spec.onEditingStatusChange(id, true);\n\n newFilenameInputEl.value = getFilenameSansExtension(id);\n\n if (focusInput) {\n newFilenameInputEl.focus();\n }\n\n registerInputBlurHandler(newFilenameInputEl, id);\n registerInputEnterKeyHandler(newFilenameInputEl, id);\n }\n });\n};\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n/**\n * CryptoJS core components.\n */\nqq.CryptoJS = (function (Math, undefined) {\n /**\n * CryptoJS namespace.\n */\n var C = {};\n\n /**\n * Library namespace.\n */\n var C_lib = C.lib = {};\n\n /**\n * Base object for prototypal inheritance.\n */\n var Base = C_lib.Base = (function () {\n function F() {}\n\n return {\n /**\n * Creates a new object that inherits from this object.\n *\n * @param {Object} overrides Properties to copy into the new object.\n *\n * @return {Object} The new object.\n *\n * @static\n *\n * @example\n *\n * var MyType = CryptoJS.lib.Base.extend({\n * field: 'value',\n *\n * method: function () {\n * }\n * });\n */\n extend: function (overrides) {\n // Spawn\n F.prototype = this;\n var subtype = new F();\n\n // Augment\n if (overrides) {\n subtype.mixIn(overrides);\n }\n\n // Create default initializer\n if (!subtype.hasOwnProperty('init')) {\n subtype.init = function () {\n subtype.$super.init.apply(this, arguments);\n };\n }\n\n // Initializer's prototype is the subtype object\n subtype.init.prototype = subtype;\n\n // Reference supertype\n subtype.$super = this;\n\n return subtype;\n },\n\n /**\n * Extends this object and runs the init method.\n * Arguments to create() will be passed to init().\n *\n * @return {Object} The new object.\n *\n * @static\n *\n * @example\n *\n * var instance = MyType.create();\n */\n create: function () {\n var instance = this.extend();\n instance.init.apply(instance, arguments);\n\n return instance;\n },\n\n /**\n * Initializes a newly created object.\n * Override this method to add some logic when your objects are created.\n *\n * @example\n *\n * var MyType = CryptoJS.lib.Base.extend({\n * init: function () {\n * // ...\n * }\n * });\n */\n init: function () {\n },\n\n /**\n * Copies properties into this object.\n *\n * @param {Object} properties The properties to mix in.\n *\n * @example\n *\n * MyType.mixIn({\n * field: 'value'\n * });\n */\n mixIn: function (properties) {\n for (var propertyName in properties) {\n if (properties.hasOwnProperty(propertyName)) {\n this[propertyName] = properties[propertyName];\n }\n }\n\n // IE won't copy toString using the loop above\n if (properties.hasOwnProperty('toString')) {\n this.toString = properties.toString;\n }\n },\n\n /**\n * Creates a copy of this object.\n *\n * @return {Object} The clone.\n *\n * @example\n *\n * var clone = instance.clone();\n */\n clone: function () {\n return this.init.prototype.extend(this);\n }\n };\n }());\n\n /**\n * An array of 32-bit words.\n *\n * @property {Array} words The array of 32-bit words.\n * @property {number} sigBytes The number of significant bytes in this word array.\n */\n var WordArray = C_lib.WordArray = Base.extend({\n /**\n * Initializes a newly created word array.\n *\n * @param {Array} words (Optional) An array of 32-bit words.\n * @param {number} sigBytes (Optional) The number of significant bytes in the words.\n *\n * @example\n *\n * var wordArray = CryptoJS.lib.WordArray.create();\n * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);\n * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);\n */\n init: function (words, sigBytes) {\n words = this.words = words || [];\n\n if (sigBytes != undefined) {\n this.sigBytes = sigBytes;\n } else {\n this.sigBytes = words.length * 4;\n }\n },\n\n /**\n * Converts this word array to a string.\n *\n * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex\n *\n * @return {string} The stringified word array.\n *\n * @example\n *\n * var string = wordArray + '';\n * var string = wordArray.toString();\n * var string = wordArray.toString(CryptoJS.enc.Utf8);\n */\n toString: function (encoder) {\n return (encoder || Hex).stringify(this);\n },\n\n /**\n * Concatenates a word array to this word array.\n *\n * @param {WordArray} wordArray The word array to append.\n *\n * @return {WordArray} This word array.\n *\n * @example\n *\n * wordArray1.concat(wordArray2);\n */\n concat: function (wordArray) {\n // Shortcuts\n var thisWords = this.words;\n var thatWords = wordArray.words;\n var thisSigBytes = this.sigBytes;\n var thatSigBytes = wordArray.sigBytes;\n\n // Clamp excess bits\n this.clamp();\n\n // Concat\n if (thisSigBytes % 4) {\n // Copy one byte at a time\n for (var i = 0; i < thatSigBytes; i++) {\n var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);\n }\n } else if (thatWords.length > 0xffff) {\n // Copy one word at a time\n for (var i = 0; i < thatSigBytes; i += 4) {\n thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];\n }\n } else {\n // Copy all words at once\n thisWords.push.apply(thisWords, thatWords);\n }\n this.sigBytes += thatSigBytes;\n\n // Chainable\n return this;\n },\n\n /**\n * Removes insignificant bits.\n *\n * @example\n *\n * wordArray.clamp();\n */\n clamp: function () {\n // Shortcuts\n var words = this.words;\n var sigBytes = this.sigBytes;\n\n // Clamp\n words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);\n words.length = Math.ceil(sigBytes / 4);\n },\n\n /**\n * Creates a copy of this word array.\n *\n * @return {WordArray} The clone.\n *\n * @example\n *\n * var clone = wordArray.clone();\n */\n clone: function () {\n var clone = Base.clone.call(this);\n clone.words = this.words.slice(0);\n\n return clone;\n },\n\n /**\n * Creates a word array filled with random bytes.\n *\n * @param {number} nBytes The number of random bytes to generate.\n *\n * @return {WordArray} The random word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.lib.WordArray.random(16);\n */\n random: function (nBytes) {\n var words = [];\n for (var i = 0; i < nBytes; i += 4) {\n words.push((Math.random() * 0x100000000) | 0);\n }\n\n return new WordArray.init(words, nBytes);\n }\n });\n\n /**\n * Encoder namespace.\n */\n var C_enc = C.enc = {};\n\n /**\n * Hex encoding strategy.\n */\n var Hex = C_enc.Hex = {\n /**\n * Converts a word array to a hex string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The hex string.\n *\n * @static\n *\n * @example\n *\n * var hexString = CryptoJS.enc.Hex.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n\n // Convert\n var hexChars = [];\n for (var i = 0; i < sigBytes; i++) {\n var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n hexChars.push((bite >>> 4).toString(16));\n hexChars.push((bite & 0x0f).toString(16));\n }\n\n return hexChars.join('');\n },\n\n /**\n * Converts a hex string to a word array.\n *\n * @param {string} hexStr The hex string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Hex.parse(hexString);\n */\n parse: function (hexStr) {\n // Shortcut\n var hexStrLength = hexStr.length;\n\n // Convert\n var words = [];\n for (var i = 0; i < hexStrLength; i += 2) {\n words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);\n }\n\n return new WordArray.init(words, hexStrLength / 2);\n }\n };\n\n /**\n * Latin1 encoding strategy.\n */\n var Latin1 = C_enc.Latin1 = {\n /**\n * Converts a word array to a Latin1 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Latin1 string.\n *\n * @static\n *\n * @example\n *\n * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n\n // Convert\n var latin1Chars = [];\n for (var i = 0; i < sigBytes; i++) {\n var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n latin1Chars.push(String.fromCharCode(bite));\n }\n\n return latin1Chars.join('');\n },\n\n /**\n * Converts a Latin1 string to a word array.\n *\n * @param {string} latin1Str The Latin1 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Latin1.parse(latin1String);\n */\n parse: function (latin1Str) {\n // Shortcut\n var latin1StrLength = latin1Str.length;\n\n // Convert\n var words = [];\n for (var i = 0; i < latin1StrLength; i++) {\n words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);\n }\n\n return new WordArray.init(words, latin1StrLength);\n }\n };\n\n /**\n * UTF-8 encoding strategy.\n */\n var Utf8 = C_enc.Utf8 = {\n /**\n * Converts a word array to a UTF-8 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The UTF-8 string.\n *\n * @static\n *\n * @example\n *\n * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);\n */\n stringify: function (wordArray) {\n try {\n return decodeURIComponent(escape(Latin1.stringify(wordArray)));\n } catch (e) {\n throw new Error('Malformed UTF-8 data');\n }\n },\n\n /**\n * Converts a UTF-8 string to a word array.\n *\n * @param {string} utf8Str The UTF-8 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Utf8.parse(utf8String);\n */\n parse: function (utf8Str) {\n return Latin1.parse(unescape(encodeURIComponent(utf8Str)));\n }\n };\n\n /**\n * Abstract buffered block algorithm template.\n *\n * The property blockSize must be implemented in a concrete subtype.\n *\n * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0\n */\n var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({\n /**\n * Resets this block algorithm's data buffer to its initial state.\n *\n * @example\n *\n * bufferedBlockAlgorithm.reset();\n */\n reset: function () {\n // Initial values\n this._data = new WordArray.init();\n this._nDataBytes = 0;\n },\n\n /**\n * Adds new data to this block algorithm's buffer.\n *\n * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.\n *\n * @example\n *\n * bufferedBlockAlgorithm._append('data');\n * bufferedBlockAlgorithm._append(wordArray);\n */\n _append: function (data) {\n // Convert string to WordArray, else assume WordArray already\n if (typeof data == 'string') {\n data = Utf8.parse(data);\n }\n\n // Append\n this._data.concat(data);\n this._nDataBytes += data.sigBytes;\n },\n\n /**\n * Processes available data blocks.\n *\n * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.\n *\n * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.\n *\n * @return {WordArray} The processed data.\n *\n * @example\n *\n * var processedData = bufferedBlockAlgorithm._process();\n * var processedData = bufferedBlockAlgorithm._process(!!'flush');\n */\n _process: function (doFlush) {\n // Shortcuts\n var data = this._data;\n var dataWords = data.words;\n var dataSigBytes = data.sigBytes;\n var blockSize = this.blockSize;\n var blockSizeBytes = blockSize * 4;\n\n // Count blocks ready\n var nBlocksReady = dataSigBytes / blockSizeBytes;\n if (doFlush) {\n // Round up to include partial blocks\n nBlocksReady = Math.ceil(nBlocksReady);\n } else {\n // Round down to include only full blocks,\n // less the number of blocks that must remain in the buffer\n nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);\n }\n\n // Count words ready\n var nWordsReady = nBlocksReady * blockSize;\n\n // Count bytes ready\n var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);\n\n // Process blocks\n if (nWordsReady) {\n for (var offset = 0; offset < nWordsReady; offset += blockSize) {\n // Perform concrete-algorithm logic\n this._doProcessBlock(dataWords, offset);\n }\n\n // Remove processed words\n var processedWords = dataWords.splice(0, nWordsReady);\n data.sigBytes -= nBytesReady;\n }\n\n // Return processed words\n return new WordArray.init(processedWords, nBytesReady);\n },\n\n /**\n * Creates a copy of this object.\n *\n * @return {Object} The clone.\n *\n * @example\n *\n * var clone = bufferedBlockAlgorithm.clone();\n */\n clone: function () {\n var clone = Base.clone.call(this);\n clone._data = this._data.clone();\n\n return clone;\n },\n\n _minBufferSize: 0\n });\n\n /**\n * Abstract hasher template.\n *\n * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)\n */\n var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({\n /**\n * Configuration options.\n */\n cfg: Base.extend(),\n\n /**\n * Initializes a newly created hasher.\n *\n * @param {Object} cfg (Optional) The configuration options to use for this hash computation.\n *\n * @example\n *\n * var hasher = CryptoJS.algo.SHA256.create();\n */\n init: function (cfg) {\n // Apply config defaults\n this.cfg = this.cfg.extend(cfg);\n\n // Set initial values\n this.reset();\n },\n\n /**\n * Resets this hasher to its initial state.\n *\n * @example\n *\n * hasher.reset();\n */\n reset: function () {\n // Reset data buffer\n BufferedBlockAlgorithm.reset.call(this);\n\n // Perform concrete-hasher logic\n this._doReset();\n },\n\n /**\n * Updates this hasher with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {Hasher} This hasher.\n *\n * @example\n *\n * hasher.update('message');\n * hasher.update(wordArray);\n */\n update: function (messageUpdate) {\n // Append\n this._append(messageUpdate);\n\n // Update the hash\n this._process();\n\n // Chainable\n return this;\n },\n\n /**\n * Finalizes the hash computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The hash.\n *\n * @example\n *\n * var hash = hasher.finalize();\n * var hash = hasher.finalize('message');\n * var hash = hasher.finalize(wordArray);\n */\n finalize: function (messageUpdate) {\n // Final message update\n if (messageUpdate) {\n this._append(messageUpdate);\n }\n\n // Perform concrete-hasher logic\n var hash = this._doFinalize();\n\n return hash;\n },\n\n blockSize: 512/32,\n\n /**\n * Creates a shortcut function to a hasher's object interface.\n *\n * @param {Hasher} hasher The hasher to create a helper for.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);\n */\n _createHelper: function (hasher) {\n return function (message, cfg) {\n return new hasher.init(cfg).finalize(message);\n };\n },\n\n /**\n * Creates a shortcut function to the HMAC's object interface.\n *\n * @param {Hasher} hasher The hasher to use in this HMAC helper.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);\n */\n _createHmacHelper: function (hasher) {\n return function (message, key) {\n return new C_algo.HMAC.init(hasher, key).finalize(message);\n };\n }\n });\n\n /**\n * Algorithm namespace.\n */\n var C_algo = C.algo = {};\n\n return C;\n}(Math));\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var WordArray = C_lib.WordArray;\n var C_enc = C.enc;\n\n /**\n * Base64 encoding strategy.\n */\n var Base64 = C_enc.Base64 = {\n /**\n * Converts a word array to a Base64 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Base64 string.\n *\n * @static\n *\n * @example\n *\n * var base64String = CryptoJS.enc.Base64.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n var map = this._map;\n\n // Clamp excess bits\n wordArray.clamp();\n\n // Convert\n var base64Chars = [];\n for (var i = 0; i < sigBytes; i += 3) {\n var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;\n var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;\n\n var triplet = (byte1 << 16) | (byte2 << 8) | byte3;\n\n for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {\n base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));\n }\n }\n\n // Add padding\n var paddingChar = map.charAt(64);\n if (paddingChar) {\n while (base64Chars.length % 4) {\n base64Chars.push(paddingChar);\n }\n }\n\n return base64Chars.join('');\n },\n\n /**\n * Converts a Base64 string to a word array.\n *\n * @param {string} base64Str The Base64 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Base64.parse(base64String);\n */\n parse: function (base64Str) {\n // Shortcuts\n var base64StrLength = base64Str.length;\n var map = this._map;\n\n // Ignore padding\n var paddingChar = map.charAt(64);\n if (paddingChar) {\n var paddingIndex = base64Str.indexOf(paddingChar);\n if (paddingIndex != -1) {\n base64StrLength = paddingIndex;\n }\n }\n\n // Convert\n var words = [];\n var nBytes = 0;\n for (var i = 0; i < base64StrLength; i++) {\n if (i % 4) {\n var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2);\n var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2);\n words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8);\n nBytes++;\n }\n }\n\n return WordArray.create(words, nBytes);\n },\n\n _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='\n };\n}());\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var Base = C_lib.Base;\n var C_enc = C.enc;\n var Utf8 = C_enc.Utf8;\n var C_algo = C.algo;\n\n /**\n * HMAC algorithm.\n */\n var HMAC = C_algo.HMAC = Base.extend({\n /**\n * Initializes a newly created HMAC.\n *\n * @param {Hasher} hasher The hash algorithm to use.\n * @param {WordArray|string} key The secret key.\n *\n * @example\n *\n * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);\n */\n init: function (hasher, key) {\n // Init hasher\n hasher = this._hasher = new hasher.init();\n\n // Convert string to WordArray, else assume WordArray already\n if (typeof key == 'string') {\n key = Utf8.parse(key);\n }\n\n // Shortcuts\n var hasherBlockSize = hasher.blockSize;\n var hasherBlockSizeBytes = hasherBlockSize * 4;\n\n // Allow arbitrary length keys\n if (key.sigBytes > hasherBlockSizeBytes) {\n key = hasher.finalize(key);\n }\n\n // Clamp excess bits\n key.clamp();\n\n // Clone key for inner and outer pads\n var oKey = this._oKey = key.clone();\n var iKey = this._iKey = key.clone();\n\n // Shortcuts\n var oKeyWords = oKey.words;\n var iKeyWords = iKey.words;\n\n // XOR keys with pad constants\n for (var i = 0; i < hasherBlockSize; i++) {\n oKeyWords[i] ^= 0x5c5c5c5c;\n iKeyWords[i] ^= 0x36363636;\n }\n oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;\n\n // Set initial values\n this.reset();\n },\n\n /**\n * Resets this HMAC to its initial state.\n *\n * @example\n *\n * hmacHasher.reset();\n */\n reset: function () {\n // Shortcut\n var hasher = this._hasher;\n\n // Reset\n hasher.reset();\n hasher.update(this._iKey);\n },\n\n /**\n * Updates this HMAC with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {HMAC} This HMAC instance.\n *\n * @example\n *\n * hmacHasher.update('message');\n * hmacHasher.update(wordArray);\n */\n update: function (messageUpdate) {\n this._hasher.update(messageUpdate);\n\n // Chainable\n return this;\n },\n\n /**\n * Finalizes the HMAC computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The HMAC.\n *\n * @example\n *\n * var hmac = hmacHasher.finalize();\n * var hmac = hmacHasher.finalize('message');\n * var hmac = hmacHasher.finalize(wordArray);\n */\n finalize: function (messageUpdate) {\n // Shortcut\n var hasher = this._hasher;\n\n // Compute HMAC\n var innerHash = hasher.finalize(messageUpdate);\n hasher.reset();\n var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));\n\n return hmac;\n }\n });\n}());\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var WordArray = C_lib.WordArray;\n var Hasher = C_lib.Hasher;\n var C_algo = C.algo;\n\n // Reusable object\n var W = [];\n\n /**\n * SHA-1 hash algorithm.\n */\n var SHA1 = C_algo.SHA1 = Hasher.extend({\n _doReset: function () {\n this._hash = new WordArray.init([\n 0x67452301, 0xefcdab89,\n 0x98badcfe, 0x10325476,\n 0xc3d2e1f0\n ]);\n },\n\n _doProcessBlock: function (M, offset) {\n // Shortcut\n var H = this._hash.words;\n\n // Working variables\n var a = H[0];\n var b = H[1];\n var c = H[2];\n var d = H[3];\n var e = H[4];\n\n // Computation\n for (var i = 0; i < 80; i++) {\n if (i < 16) {\n W[i] = M[offset + i] | 0;\n } else {\n var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];\n W[i] = (n << 1) | (n >>> 31);\n }\n\n var t = ((a << 5) | (a >>> 27)) + e + W[i];\n if (i < 20) {\n t += ((b & c) | (~b & d)) + 0x5a827999;\n } else if (i < 40) {\n t += (b ^ c ^ d) + 0x6ed9eba1;\n } else if (i < 60) {\n t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;\n } else /* if (i < 80) */ {\n t += (b ^ c ^ d) - 0x359d3e2a;\n }\n\n e = d;\n d = c;\n c = (b << 30) | (b >>> 2);\n b = a;\n a = t;\n }\n\n // Intermediate hash value\n H[0] = (H[0] + a) | 0;\n H[1] = (H[1] + b) | 0;\n H[2] = (H[2] + c) | 0;\n H[3] = (H[3] + d) | 0;\n H[4] = (H[4] + e) | 0;\n },\n\n _doFinalize: function () {\n // Shortcuts\n var data = this._data;\n var dataWords = data.words;\n\n var nBitsTotal = this._nDataBytes * 8;\n var nBitsLeft = data.sigBytes * 8;\n\n // Add padding\n dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\n data.sigBytes = dataWords.length * 4;\n\n // Hash final blocks\n this._process();\n\n // Return final computed hash\n return this._hash;\n },\n\n clone: function () {\n var clone = Hasher.clone.call(this);\n clone._hash = this._hash.clone();\n\n return clone;\n }\n });\n\n /**\n * Shortcut function to the hasher's object interface.\n *\n * @param {WordArray|string} message The message to hash.\n *\n * @return {WordArray} The hash.\n *\n * @static\n *\n * @example\n *\n * var hash = CryptoJS.SHA1('message');\n * var hash = CryptoJS.SHA1(wordArray);\n */\n C.SHA1 = Hasher._createHelper(SHA1);\n\n /**\n * Shortcut function to the HMAC's object interface.\n *\n * @param {WordArray|string} message The message to hash.\n * @param {WordArray|string} key The secret key.\n *\n * @return {WordArray} The HMAC.\n *\n * @static\n *\n * @example\n *\n * var hmac = CryptoJS.HmacSHA1(message, key);\n */\n C.HmacSHA1 = Hasher._createHmacHelper(SHA1);\n}());\n","/*\r\nCryptoJS v3.1.2\r\ncode.google.com/p/crypto-js\r\n(c) 2009-2013 by Jeff Mott. All rights reserved.\r\ncode.google.com/p/crypto-js/wiki/License\r\n*/\r\n(function (Math) {\r\n // Shortcuts\r\n var C = qq.CryptoJS;\r\n var C_lib = C.lib;\r\n var WordArray = C_lib.WordArray;\r\n var Hasher = C_lib.Hasher;\r\n var C_algo = C.algo;\r\n\r\n // Initialization and round constants tables\r\n var H = [];\r\n var K = [];\r\n\r\n // Compute constants\r\n (function () {\r\n function isPrime(n) {\r\n var sqrtN = Math.sqrt(n);\r\n for (var factor = 2; factor <= sqrtN; factor++) {\r\n if (!(n % factor)) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n function getFractionalBits(n) {\r\n return ((n - (n | 0)) * 0x100000000) | 0;\r\n }\r\n\r\n var n = 2;\r\n var nPrime = 0;\r\n while (nPrime < 64) {\r\n if (isPrime(n)) {\r\n if (nPrime < 8) {\r\n H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));\r\n }\r\n K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));\r\n\r\n nPrime++;\r\n }\r\n\r\n n++;\r\n }\r\n }());\r\n\r\n // Reusable object\r\n var W = [];\r\n\r\n /**\r\n * SHA-256 hash algorithm.\r\n */\r\n var SHA256 = C_algo.SHA256 = Hasher.extend({\r\n _doReset: function () {\r\n this._hash = new WordArray.init(H.slice(0));\r\n },\r\n\r\n _doProcessBlock: function (M, offset) {\r\n // Shortcut\r\n var H = this._hash.words;\r\n\r\n // Working variables\r\n var a = H[0];\r\n var b = H[1];\r\n var c = H[2];\r\n var d = H[3];\r\n var e = H[4];\r\n var f = H[5];\r\n var g = H[6];\r\n var h = H[7];\r\n\r\n // Computation\r\n for (var i = 0; i < 64; i++) {\r\n if (i < 16) {\r\n W[i] = M[offset + i] | 0;\r\n } else {\r\n var gamma0x = W[i - 15];\r\n var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^\r\n ((gamma0x << 14) | (gamma0x >>> 18)) ^\r\n (gamma0x >>> 3);\r\n\r\n var gamma1x = W[i - 2];\r\n var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^\r\n ((gamma1x << 13) | (gamma1x >>> 19)) ^\r\n (gamma1x >>> 10);\r\n\r\n W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];\r\n }\r\n\r\n var ch = (e & f) ^ (~e & g);\r\n var maj = (a & b) ^ (a & c) ^ (b & c);\r\n\r\n var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));\r\n var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25));\r\n\r\n var t1 = h + sigma1 + ch + K[i] + W[i];\r\n var t2 = sigma0 + maj;\r\n\r\n h = g;\r\n g = f;\r\n f = e;\r\n e = (d + t1) | 0;\r\n d = c;\r\n c = b;\r\n b = a;\r\n a = (t1 + t2) | 0;\r\n }\r\n\r\n // Intermediate hash value\r\n H[0] = (H[0] + a) | 0;\r\n H[1] = (H[1] + b) | 0;\r\n H[2] = (H[2] + c) | 0;\r\n H[3] = (H[3] + d) | 0;\r\n H[4] = (H[4] + e) | 0;\r\n H[5] = (H[5] + f) | 0;\r\n H[6] = (H[6] + g) | 0;\r\n H[7] = (H[7] + h) | 0;\r\n },\r\n\r\n _doFinalize: function () {\r\n // Shortcuts\r\n var data = this._data;\r\n var dataWords = data.words;\r\n\r\n var nBitsTotal = this._nDataBytes * 8;\r\n var nBitsLeft = data.sigBytes * 8;\r\n\r\n // Add padding\r\n dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\r\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\r\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\r\n data.sigBytes = dataWords.length * 4;\r\n\r\n // Hash final blocks\r\n this._process();\r\n\r\n // Return final computed hash\r\n return this._hash;\r\n },\r\n\r\n clone: function () {\r\n var clone = Hasher.clone.call(this);\r\n clone._hash = this._hash.clone();\r\n\r\n return clone;\r\n }\r\n });\r\n\r\n /**\r\n * Shortcut function to the hasher's object interface.\r\n *\r\n * @param {WordArray|string} message The message to hash.\r\n *\r\n * @return {WordArray} The hash.\r\n *\r\n * @static\r\n *\r\n * @example\r\n *\r\n * var hash = CryptoJS.SHA256('message');\r\n * var hash = CryptoJS.SHA256(wordArray);\r\n */\r\n C.SHA256 = Hasher._createHelper(SHA256);\r\n\r\n /**\r\n * Shortcut function to the HMAC's object interface.\r\n *\r\n * @param {WordArray|string} message The message to hash.\r\n * @param {WordArray|string} key The secret key.\r\n *\r\n * @return {WordArray} The HMAC.\r\n *\r\n * @static\r\n *\r\n * @example\r\n *\r\n * var hmac = CryptoJS.HmacSHA256(message, key);\r\n */\r\n C.HmacSHA256 = Hasher._createHmacHelper(SHA256);\r\n}(Math));\r\n","/*\r\nCryptoJS v3.1.2\r\ncode.google.com/p/crypto-js\r\n(c) 2009-2013 by Jeff Mott. All rights reserved.\r\ncode.google.com/p/crypto-js/wiki/License\r\n*/\r\n(function () {\r\n // Check if typed arrays are supported\r\n if (typeof ArrayBuffer != 'function') {\r\n return;\r\n }\r\n\r\n // Shortcuts\r\n var C = qq.CryptoJS;\r\n var C_lib = C.lib;\r\n var WordArray = C_lib.WordArray;\r\n\r\n // Reference original init\r\n var superInit = WordArray.init;\r\n\r\n // Augment WordArray.init to handle typed arrays\r\n var subInit = WordArray.init = function (typedArray) {\r\n // Convert buffers to uint8\r\n if (typedArray instanceof ArrayBuffer) {\r\n typedArray = new Uint8Array(typedArray);\r\n }\r\n\r\n // Convert other array views to uint8\r\n if (\r\n typedArray instanceof Int8Array ||\r\n typedArray instanceof Uint8ClampedArray ||\r\n typedArray instanceof Int16Array ||\r\n typedArray instanceof Uint16Array ||\r\n typedArray instanceof Int32Array ||\r\n typedArray instanceof Uint32Array ||\r\n typedArray instanceof Float32Array ||\r\n typedArray instanceof Float64Array\r\n ) {\r\n typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);\r\n }\r\n\r\n // Handle Uint8Array\r\n if (typedArray instanceof Uint8Array) {\r\n // Shortcut\r\n var typedArrayByteLength = typedArray.byteLength;\r\n\r\n // Extract bytes\r\n var words = [];\r\n for (var i = 0; i < typedArrayByteLength; i++) {\r\n words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8);\r\n }\r\n\r\n // Initialize this word array\r\n superInit.call(this, words, typedArrayByteLength);\r\n } else {\r\n // Else call normal init\r\n superInit.apply(this, arguments);\r\n }\r\n };\r\n\r\n subInit.prototype = WordArray;\r\n}());\r\n","/*globals qq */\nqq.s3 = qq.s3 || {};\n\nqq.s3.util = qq.s3.util || (function() {\n \"use strict\";\n\n return {\n ALGORITHM_PARAM_NAME: \"x-amz-algorithm\",\n\n AWS_PARAM_PREFIX: \"x-amz-meta-\",\n\n CREDENTIAL_PARAM_NAME: \"x-amz-credential\",\n\n DATE_PARAM_NAME: \"x-amz-date\",\n\n REDUCED_REDUNDANCY_PARAM_NAME: \"x-amz-storage-class\",\n REDUCED_REDUNDANCY_PARAM_VALUE: \"REDUCED_REDUNDANCY\",\n\n SERVER_SIDE_ENCRYPTION_PARAM_NAME: \"x-amz-server-side-encryption\",\n SERVER_SIDE_ENCRYPTION_PARAM_VALUE: \"AES256\",\n\n SESSION_TOKEN_PARAM_NAME: \"x-amz-security-token\",\n\n V4_ALGORITHM_PARAM_VALUE: \"AWS4-HMAC-SHA256\",\n\n V4_SIGNATURE_PARAM_NAME: \"x-amz-signature\",\n\n CASE_SENSITIVE_PARAM_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\"\n ],\n\n UNSIGNABLE_REST_HEADER_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\"\n ],\n\n UNPREFIXED_PARAM_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\",\n \"x-amz-server-side-encryption-customer-algorithm\",\n \"x-amz-server-side-encryption-customer-key\",\n \"x-amz-server-side-encryption-customer-key-MD5\"\n ],\n\n /**\n * This allows for the region to be specified in the bucket's endpoint URL, or not.\n *\n * Examples of some valid endpoints are:\n * http://foo.s3.amazonaws.com\n * https://foo.s3.amazonaws.com\n * http://foo.s3-ap-northeast-1.amazonaws.com\n * foo.s3.amazonaws.com\n * http://foo.bar.com\n * http://s3.amazonaws.com/foo.bar.com\n * ...etc\n *\n * @param endpoint The bucket's URL.\n * @returns {String || undefined} The bucket name, or undefined if the URL cannot be parsed.\n */\n getBucket: function(endpoint) {\n var patterns = [\n //bucket in domain\n /^(?:https?:\\/\\/)?([a-z0-9.\\-_]+)\\.s3(?:-[a-z0-9\\-]+)?\\.amazonaws\\.com/i,\n //bucket in path\n /^(?:https?:\\/\\/)?s3(?:-[a-z0-9\\-]+)?\\.amazonaws\\.com\\/([a-z0-9.\\-_]+)/i,\n //custom domain\n /^(?:https?:\\/\\/)?([a-z0-9.\\-_]+)/i\n ],\n bucket;\n\n qq.each(patterns, function(idx, pattern) {\n var match = pattern.exec(endpoint);\n\n if (match) {\n bucket = match[1];\n return false;\n }\n });\n\n return bucket;\n },\n\n /** Create Prefixed request headers which are appropriate for S3.\n *\n * If the request header is appropriate for S3 (e.g. Cache-Control) then pass\n * it along without a metadata prefix. For all other request header parameter names,\n * apply qq.s3.util.AWS_PARAM_PREFIX before the name.\n * See: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html\n */\n _getPrefixedParamName: function(name) {\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {\n return name;\n }\n return qq.s3.util.AWS_PARAM_PREFIX + name;\n },\n\n /**\n * Create a policy document to be signed and sent along with the S3 upload request.\n *\n * @param spec Object with properties use to construct the policy document.\n * @returns {Object} Policy doc.\n */\n getPolicy: function(spec) {\n var policy = {},\n conditions = [],\n bucket = spec.bucket,\n date = spec.date,\n drift = spec.clockDrift,\n key = spec.key,\n accessKey = spec.accessKey,\n acl = spec.acl,\n type = spec.type,\n expectedStatus = spec.expectedStatus,\n sessionToken = spec.sessionToken,\n params = spec.params,\n successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl),\n minFileSize = spec.minFileSize,\n maxFileSize = spec.maxFileSize,\n reducedRedundancy = spec.reducedRedundancy,\n region = spec.region,\n serverSideEncryption = spec.serverSideEncryption,\n signatureVersion = spec.signatureVersion;\n\n policy.expiration = qq.s3.util.getPolicyExpirationDate(date, drift);\n\n conditions.push({acl: acl});\n conditions.push({bucket: bucket});\n\n if (type) {\n conditions.push({\"Content-Type\": type});\n }\n\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (expectedStatus) {\n conditions.push({success_action_status: expectedStatus.toString()});\n }\n\n if (successRedirectUrl) {\n conditions.push({success_action_redirect: successRedirectUrl});\n }\n // jscs:enable\n if (reducedRedundancy) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (sessionToken) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n if (serverSideEncryption) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n if (signatureVersion === 2) {\n conditions.push({key: key});\n }\n else if (signatureVersion === 4) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;\n\n conditions.push({});\n conditions[conditions.length - 1].key = key;\n\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.CREDENTIAL_PARAM_NAME] =\n qq.s3.util.getV4CredentialsString({date: date, key: accessKey, region: region});\n\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.DATE_PARAM_NAME] =\n qq.s3.util.getV4PolicyDate(date, drift);\n }\n\n // user metadata\n qq.each(params, function(name, val) {\n var awsParamName = qq.s3.util._getPrefixedParamName(name),\n param = {};\n\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {\n param[awsParamName] = val;\n }\n else {\n param[awsParamName] = encodeURIComponent(val);\n }\n\n conditions.push(param);\n });\n\n policy.conditions = conditions;\n\n qq.s3.util.enforceSizeLimits(policy, minFileSize, maxFileSize);\n\n return policy;\n },\n\n /**\n * Update a previously constructed policy document with updated credentials. Currently, this only requires we\n * update the session token. This is only relevant if requests are being signed client-side.\n *\n * @param policy Live policy document\n * @param newSessionToken Updated session token.\n */\n refreshPolicyCredentials: function(policy, newSessionToken) {\n var sessionTokenFound = false;\n\n qq.each(policy.conditions, function(oldCondIdx, oldCondObj) {\n qq.each(oldCondObj, function(oldCondName, oldCondVal) {\n if (oldCondName === qq.s3.util.SESSION_TOKEN_PARAM_NAME) {\n oldCondObj[oldCondName] = newSessionToken;\n sessionTokenFound = true;\n }\n });\n });\n\n if (!sessionTokenFound) {\n policy.conditions.push({});\n policy.conditions[policy.conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = newSessionToken;\n }\n },\n\n /**\n * Generates all parameters to be passed along with the S3 upload request. This includes invoking a callback\n * that is expected to asynchronously retrieve a signature for the policy document. Note that the server\n * signing the request should reject a \"tainted\" policy document that includes unexpected values, since it is\n * still possible for a malicious user to tamper with these values during policy document generation,\n * before it is sent to the server for signing.\n *\n * @param spec Object with properties: `params`, `type`, `key`, `accessKey`, `acl`, `expectedStatus`, `successRedirectUrl`,\n * `reducedRedundancy`, `region`, `serverSideEncryption`, `version`, and `log()`, along with any options associated with `qq.s3.util.getPolicy()`.\n * @returns {qq.Promise} Promise that will be fulfilled once all parameters have been determined.\n */\n generateAwsParams: function(spec, signPolicyCallback) {\n var awsParams = {},\n customParams = spec.params,\n promise = new qq.Promise(),\n sessionToken = spec.sessionToken,\n drift = spec.clockDrift,\n type = spec.type,\n key = spec.key,\n accessKey = spec.accessKey,\n acl = spec.acl,\n expectedStatus = spec.expectedStatus,\n successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl),\n reducedRedundancy = spec.reducedRedundancy,\n region = spec.region,\n serverSideEncryption = spec.serverSideEncryption,\n signatureVersion = spec.signatureVersion,\n now = new Date(),\n log = spec.log,\n policyJson;\n\n spec.date = now;\n policyJson = qq.s3.util.getPolicy(spec);\n\n awsParams.key = key;\n\n if (type) {\n awsParams[\"Content-Type\"] = type;\n }\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (expectedStatus) {\n awsParams.success_action_status = expectedStatus;\n }\n\n if (successRedirectUrl) {\n awsParams.success_action_redirect = successRedirectUrl;\n }\n // jscs:enable\n if (reducedRedundancy) {\n awsParams[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (serverSideEncryption) {\n awsParams[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n if (sessionToken) {\n awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n awsParams.acl = acl;\n\n // Custom (user-supplied) params must be prefixed with the value of `qq.s3.util.AWS_PARAM_PREFIX`.\n // Params such as Cache-Control or Content-Disposition will not be prefixed.\n // Prefixed param values will be URI encoded as well.\n qq.each(customParams, function(name, val) {\n var awsParamName = qq.s3.util._getPrefixedParamName(name);\n\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {\n awsParams[awsParamName] = val;\n }\n else {\n awsParams[awsParamName] = encodeURIComponent(val);\n }\n });\n\n if (signatureVersion === 2) {\n awsParams.AWSAccessKeyId = accessKey;\n }\n else if (signatureVersion === 4) {\n awsParams[qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;\n awsParams[qq.s3.util.CREDENTIAL_PARAM_NAME] = qq.s3.util.getV4CredentialsString({date: now, key: accessKey, region: region});\n awsParams[qq.s3.util.DATE_PARAM_NAME] = qq.s3.util.getV4PolicyDate(now, drift);\n }\n\n // Invoke a promissory callback that should provide us with a base64-encoded policy doc and an\n // HMAC signature for the policy doc.\n signPolicyCallback(policyJson).then(\n function(policyAndSignature, updatedAccessKey, updatedSessionToken) {\n awsParams.policy = policyAndSignature.policy;\n\n if (spec.signatureVersion === 2) {\n awsParams.signature = policyAndSignature.signature;\n\n if (updatedAccessKey) {\n awsParams.AWSAccessKeyId = updatedAccessKey;\n }\n }\n else if (spec.signatureVersion === 4) {\n awsParams[qq.s3.util.V4_SIGNATURE_PARAM_NAME] = policyAndSignature.signature;\n }\n\n if (updatedSessionToken) {\n awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;\n }\n\n promise.success(awsParams);\n },\n function(errorMessage) {\n errorMessage = errorMessage || \"Can't continue further with request to S3 as we did not receive \" +\n \"a valid signature and policy from the server.\";\n\n log(\"Policy signing failed. \" + errorMessage, \"error\");\n promise.failure(errorMessage);\n }\n );\n\n return promise;\n },\n\n /**\n * Add a condition to an existing S3 upload request policy document used to ensure AWS enforces any size\n * restrictions placed on files server-side. This is important to do, in case users mess with the client-side\n * checks already in place.\n *\n * @param policy Policy document as an `Object`, with a `conditions` property already attached\n * @param minSize Minimum acceptable size, in bytes\n * @param maxSize Maximum acceptable size, in bytes (0 = unlimited)\n */\n enforceSizeLimits: function(policy, minSize, maxSize) {\n var adjustedMinSize = minSize < 0 ? 0 : minSize,\n // Adjust a maxSize of 0 to the largest possible integer, since we must specify a high and a low in the request\n adjustedMaxSize = maxSize <= 0 ? 9007199254740992 : maxSize;\n\n if (minSize > 0 || maxSize > 0) {\n policy.conditions.push([\"content-length-range\", adjustedMinSize.toString(), adjustedMaxSize.toString()]);\n }\n },\n\n getPolicyExpirationDate: function(date, drift) {\n var adjustedDate = new Date(date.getTime() + drift);\n return qq.s3.util.getPolicyDate(adjustedDate, 5);\n },\n\n getCredentialsDate: function(date) {\n return date.getUTCFullYear() + \"\" +\n (\"0\" + (date.getUTCMonth() + 1)).slice(-2) +\n (\"0\" + date.getUTCDate()).slice(-2);\n },\n\n getPolicyDate: function(date, _minutesToAdd_) {\n var minutesToAdd = _minutesToAdd_ || 0,\n pad, r;\n\n /*jshint -W014 */\n // Is this going to be a problem if we encounter this moments before 2 AM just before daylight savings time ends?\n date.setMinutes(date.getMinutes() + (minutesToAdd || 0));\n\n if (Date.prototype.toISOString) {\n return date.toISOString();\n }\n else {\n pad = function(number) {\n r = String(number);\n\n if (r.length === 1) {\n r = \"0\" + r;\n }\n\n return r;\n };\n\n return date.getUTCFullYear()\n + \"-\" + pad(date.getUTCMonth() + 1)\n + \"-\" + pad(date.getUTCDate())\n + \"T\" + pad(date.getUTCHours())\n + \":\" + pad(date.getUTCMinutes())\n + \":\" + pad(date.getUTCSeconds())\n + \".\" + String((date.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)\n + \"Z\";\n }\n },\n\n /**\n * Looks at a response from S3 contained in an iframe and parses the query string in an attempt to identify\n * the associated resource.\n *\n * @param iframe Iframe containing response\n * @returns {{bucket: *, key: *, etag: *}}\n */\n parseIframeResponse: function(iframe) {\n var doc = iframe.contentDocument || iframe.contentWindow.document,\n queryString = doc.location.search,\n match = /bucket=(.+)&key=(.+)&etag=(.+)/.exec(queryString);\n\n if (match) {\n return {\n bucket: match[1],\n key: match[2],\n etag: match[3].replace(/%22/g, \"\")\n };\n }\n },\n\n /**\n * @param successRedirectUrl Relative or absolute location of success redirect page\n * @returns {*|string} undefined if the parameter is undefined, otherwise the absolute location of the success redirect page\n */\n getSuccessRedirectAbsoluteUrl: function(successRedirectUrl) {\n if (successRedirectUrl) {\n var targetAnchorContainer = document.createElement(\"div\"),\n targetAnchor;\n\n if (qq.ie7()) {\n // Note that we must make use of `innerHTML` for IE7 only instead of simply creating an anchor via\n // `document.createElement('a')` and setting the `href` attribute. The latter approach does not allow us to\n // obtain an absolute URL in IE7 if the `endpoint` is a relative URL.\n targetAnchorContainer.innerHTML = \" \";\n targetAnchor = targetAnchorContainer.firstChild;\n return targetAnchor.href;\n }\n else {\n // IE8 and IE9 do not seem to derive an absolute URL from a relative URL using the `innerHTML`\n // approach above, so we'll just create an anchor this way and set it's `href` attribute.\n // Due to yet another quirk in IE8 and IE9, we have to set the `href` equal to itself\n // in order to ensure relative URLs will be properly parsed.\n targetAnchor = document.createElement(\"a\");\n targetAnchor.href = successRedirectUrl;\n targetAnchor.href = targetAnchor.href;\n return targetAnchor.href;\n }\n }\n },\n\n getV4CredentialsString: function(spec) {\n return spec.key + \"/\" +\n qq.s3.util.getCredentialsDate(spec.date) + \"/\" +\n spec.region + \"/s3/aws4_request\";\n },\n\n getV4PolicyDate: function(date, drift) {\n var adjustedDate = new Date(date.getTime() + drift);\n\n return qq.s3.util.getCredentialsDate(adjustedDate) + \"T\" +\n (\"0\" + adjustedDate.getUTCHours()).slice(-2) +\n (\"0\" + adjustedDate.getUTCMinutes()).slice(-2) +\n (\"0\" + adjustedDate.getUTCSeconds()).slice(-2) +\n \"Z\";\n },\n\n // AWS employs a strict interpretation of [RFC 3986](http://tools.ietf.org/html/rfc3986#page-12).\n // So, we must ensure all reserved characters listed in the spec are percent-encoded,\n // and spaces are replaced with \"+\".\n encodeQueryStringParam: function(param) {\n var percentEncoded = encodeURIComponent(param);\n\n // %-encode characters not handled by `encodeURIComponent` (to follow RFC 3986)\n percentEncoded = percentEncoded.replace(/[!'()]/g, escape);\n\n // %-encode characters not handled by `escape` (to follow RFC 3986)\n percentEncoded = percentEncoded.replace(/\\*/g, \"%2A\");\n\n // replace percent-encoded spaces with a \"+\"\n return percentEncoded.replace(/%20/g, \"+\");\n },\n /**\n * Escapes url part as for AWS requirements\n * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js\n */\n uriEscape: function(string) {\n var output = encodeURIComponent(string);\n output = output.replace(/[^A-Za-z0-9_.~\\-%]+/g, escape);\n output = output.replace(/[*]/g, function(ch) {\n return \"%\" + ch.charCodeAt(0).toString(16).toUpperCase();\n });\n return output;\n },\n /**\n * Escapes a path as for AWS requirement\n * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js\n */\n uriEscapePath: function(path) {\n var parts = [];\n qq.each(path.split(\"/\"), function(idx, item) {\n parts.push(qq.s3.util.uriEscape(item));\n });\n return parts.join(\"/\");\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to S3, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to S3.\n * Some inherited options and API methods have a special meaning in the context of the S3 uploader.\n */\n(function() {\n \"use strict\";\n\n qq.s3.FineUploaderBasic = function(o) {\n var options = {\n request: {\n // public key (required for server-side signing, ignored if `credentials` have been provided)\n accessKey: null,\n\n // padding, in milliseconds, to add to the x-amz-date header & the policy expiration date\n clockDrift: 0\n },\n\n objectProperties: {\n acl: \"private\",\n\n // string or a function which may be promissory\n bucket: qq.bind(function(id) {\n return qq.s3.util.getBucket(this.getEndpoint(id));\n }, this),\n\n // string or a function which may be promissory - only used for V4 multipart uploads\n host: qq.bind(function(id) {\n return (/(?:http|https):\\/\\/(.+)(?:\\/.+)?/).exec(this._endpointStore.get(id))[1];\n }, this),\n\n // 'uuid', 'filename', or a function which may be promissory\n key: \"uuid\",\n\n reducedRedundancy: false,\n\n // Defined at http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\n region: \"us-east-1\",\n\n serverSideEncryption: false\n },\n\n credentials: {\n // Public key (required).\n accessKey: null,\n // Private key (required).\n secretKey: null,\n // Expiration date for the credentials (required). May be an ISO string or a `Date`.\n expiration: null,\n // Temporary credentials session token.\n // Only required for temporary credentials obtained via AssumeRoleWithWebIdentity.\n sessionToken: null\n },\n\n // All but `version` are ignored if `credentials` is provided.\n signature: {\n customHeaders: {},\n endpoint: null,\n version: 2\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n // required if non-File-API browsers, such as IE9 and older, are used\n iframeSupport: {\n localBlankPagePath: null\n },\n\n chunking: {\n // minimum part size is 5 MiB when uploading to S3\n partSize: 5242880\n },\n\n cors: {\n allowXdr: true\n },\n\n callbacks: {\n onCredentialsExpired: function() {}\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n if (!this.setCredentials(options.credentials, true)) {\n this._currentCredentials.accessKey = options.request.accessKey;\n }\n\n this._aclStore = this._createStore(options.objectProperties.acl);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds S3 keys for file representations constructed from a session request.\n this._cannedKeys = {};\n // Holds S3 buckets for file representations constructed from a session request.\n this._cannedBuckets = {};\n\n this._buckets = {};\n this._hosts = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.s3.FineUploaderBasic.prototype, {\n getBucket: function(id) {\n if (this._cannedBuckets[id] == null) {\n return this._buckets[id];\n }\n return this._cannedBuckets[id];\n },\n\n /**\n * @param id File ID\n * @returns {*} Key name associated w/ the file, if one exists\n */\n getKey: function(id) {\n /* jshint eqnull:true */\n if (this._cannedKeys[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n\n return this._cannedKeys[id];\n },\n\n /**\n * Override the parent's reset function to cleanup various S3-related items.\n */\n reset: function() {\n qq.FineUploaderBasic.prototype.reset.call(this);\n this._failedSuccessRequestCallbacks = [];\n this._buckets = {};\n this._hosts = {};\n },\n\n setCredentials: function(credentials, ignoreEmpty) {\n if (credentials && credentials.secretKey) {\n if (!credentials.accessKey) {\n throw new qq.Error(\"Invalid credentials: no accessKey\");\n }\n else if (!credentials.expiration) {\n throw new qq.Error(\"Invalid credentials: no expiration\");\n }\n else {\n this._currentCredentials = qq.extend({}, credentials);\n\n // Ensure expiration is a `Date`. If initially a string, assuming it is in ISO format.\n if (qq.isString(credentials.expiration)) {\n this._currentCredentials.expiration = new Date(credentials.expiration);\n }\n }\n\n return true;\n }\n else if (!ignoreEmpty) {\n throw new qq.Error(\"Invalid credentials parameter!\");\n }\n else {\n this._currentCredentials = {};\n }\n },\n\n setAcl: function(acl, id) {\n this._aclStore.set(acl, id);\n },\n\n /**\n * Ensures the parent's upload handler creator passes any additional S3-specific options to the handler as well\n * as information required to instantiate the specific handler based on the current browser's capabilities.\n *\n * @returns {qq.UploadHandlerController}\n * @private\n */\n _createUploadHandler: function() {\n var self = this,\n additionalOptions = {\n aclStore: this._aclStore,\n getBucket: qq.bind(this._determineBucket, this),\n getHost: qq.bind(this._determineHost, this),\n getKeyName: qq.bind(this._determineKeyName, this),\n iframeSupport: this._options.iframeSupport,\n objectProperties: this._options.objectProperties,\n signature: this._options.signature,\n clockDrift: this._options.request.clockDrift,\n // pass size limit validation values to include in the request so AWS enforces this server-side\n validation: {\n minSizeLimit: this._options.validation.minSizeLimit,\n maxSizeLimit: this._options.validation.sizeLimit\n }\n };\n\n // We assume HTTP if it is missing from the start of the endpoint string.\n qq.override(this._endpointStore, function(super_) {\n return {\n get: function(id) {\n var endpoint = super_.get(id);\n\n if (endpoint.indexOf(\"http\") < 0) {\n return \"http://\" + endpoint;\n }\n\n return endpoint;\n }\n };\n });\n\n // Some param names should be lower case to avoid signature mismatches\n qq.override(this._paramsStore, function(super_) {\n return {\n get: function(id) {\n var oldParams = super_.get(id),\n modifiedParams = {};\n\n qq.each(oldParams, function(name, val) {\n var paramName = name;\n\n if (qq.indexOf(qq.s3.util.CASE_SENSITIVE_PARAM_NAMES, paramName) < 0) {\n paramName = paramName.toLowerCase();\n }\n\n modifiedParams[paramName] = qq.isFunction(val) ? val() : val;\n });\n\n return modifiedParams;\n }\n };\n });\n\n additionalOptions.signature.credentialsProvider = {\n get: function() {\n return self._currentCredentials;\n },\n\n onExpired: function() {\n var updateCredentials = new qq.Promise(),\n callbackRetVal = self._options.callbacks.onCredentialsExpired();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n callbackRetVal.then(function(credentials) {\n try {\n self.setCredentials(credentials);\n updateCredentials.success();\n }\n catch (error) {\n self.log(\"Invalid credentials returned from onCredentialsExpired callback! (\" + error.message + \")\", \"error\");\n updateCredentials.failure(\"onCredentialsExpired did not return valid credentials.\");\n }\n }, function(errorMsg) {\n self.log(\"onCredentialsExpired callback indicated failure! (\" + errorMsg + \")\", \"error\");\n updateCredentials.failure(\"onCredentialsExpired callback failed.\");\n });\n }\n else {\n self.log(\"onCredentialsExpired callback did not return a promise!\", \"error\");\n updateCredentials.failure(\"Unexpected return value for onCredentialsExpired.\");\n }\n\n return updateCredentials;\n }\n };\n\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this, additionalOptions, \"s3\");\n },\n\n _determineObjectPropertyValue: function(id, property) {\n var maybe = this._options.objectProperties[property],\n promise = new qq.Promise(),\n self = this;\n\n if (qq.isFunction(maybe)) {\n maybe = maybe(id);\n if (qq.isGenericPromise(maybe)) {\n promise = maybe;\n }\n else {\n promise.success(maybe);\n }\n }\n else if (qq.isString(maybe)) {\n promise.success(maybe);\n }\n\n promise.then(\n function success(value) {\n self[\"_\" + property + \"s\"][id] = value;\n },\n\n function failure(errorMsg) {\n qq.log(\"Problem determining \" + property + \" for ID \" + id + \" (\" + errorMsg + \")\", \"error\");\n }\n );\n\n return promise;\n },\n\n _determineBucket: function(id) {\n return this._determineObjectPropertyValue(id, \"bucket\");\n },\n\n _determineHost: function(id) {\n return this._determineObjectPropertyValue(id, \"host\");\n },\n\n /**\n * Determine the file's key name and passes it to the caller via a promissory callback. This also may\n * delegate to an integrator-defined function that determines the file's key name on demand,\n * which also may be promissory.\n *\n * @param id ID of the file\n * @param filename Name of the file\n * @returns {qq.Promise} A promise that will be fulfilled when the key name has been determined (and will be passed to the caller via the success callback).\n * @private\n */\n _determineKeyName: function(id, filename) {\n /*jshint -W015*/\n var promise = new qq.Promise(),\n keynameLogic = this._options.objectProperties.key,\n extension = qq.getExtension(filename),\n onGetKeynameFailure = promise.failure,\n onGetKeynameSuccess = function(keyname, extension) {\n var keynameToUse = keyname;\n\n if (extension !== undefined) {\n keynameToUse += \".\" + extension;\n }\n\n promise.success(keynameToUse);\n };\n\n switch (keynameLogic) {\n case \"uuid\":\n onGetKeynameSuccess(this.getUuid(id), extension);\n break;\n case \"filename\":\n onGetKeynameSuccess(filename);\n break;\n default:\n if (qq.isFunction(keynameLogic)) {\n this._handleKeynameFunction(keynameLogic, id, onGetKeynameSuccess, onGetKeynameFailure);\n }\n else {\n this.log(keynameLogic + \" is not a valid value for the s3.keyname option!\", \"error\");\n onGetKeynameFailure();\n }\n }\n\n return promise;\n },\n\n /**\n * Called by the internal onUpload handler if the integrator has supplied a function to determine\n * the file's key name. The integrator's function may be promissory. We also need to fulfill\n * the promise contract associated with the caller as well.\n *\n * @param keynameFunc Integrator-supplied function that must be executed to determine the key name. May be promissory.\n * @param id ID of the associated file\n * @param successCallback Invoke this if key name retrieval is successful, passing in the key name.\n * @param failureCallback Invoke this if key name retrieval was unsuccessful.\n * @private\n */\n _handleKeynameFunction: function(keynameFunc, id, successCallback, failureCallback) {\n var self = this,\n onSuccess = function(keyname) {\n successCallback(keyname);\n },\n onFailure = function(reason) {\n self.log(qq.format(\"Failed to retrieve key name for {}. Reason: {}\", id, reason || \"null\"), \"error\");\n failureCallback(reason);\n },\n keyname = keynameFunc.call(this, id);\n\n if (qq.isGenericPromise(keyname)) {\n keyname.then(onSuccess, onFailure);\n }\n /*jshint -W116*/\n else if (keyname == null) {\n onFailure();\n }\n else {\n onSuccess(keyname);\n }\n },\n\n _getEndpointSpecificParams: function(id, response, maybeXhr) {\n var params = {\n key: this.getKey(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n bucket: this.getBucket(id)\n };\n\n if (maybeXhr && maybeXhr.getResponseHeader(\"ETag\")) {\n params.etag = maybeXhr.getResponseHeader(\"ETag\");\n }\n else if (response.etag) {\n params.etag = response.etag;\n }\n\n return params;\n },\n\n // Hooks into the base internal `_onSubmitDelete` to add key and bucket params to the delete file request.\n _onSubmitDelete: function(id, onSuccessCallback) {\n var additionalMandatedParams = {\n key: this.getKey(id),\n bucket: this.getBucket(id)\n };\n\n return qq.FineUploaderBasic.prototype._onSubmitDelete.call(this, id, onSuccessCallback, additionalMandatedParams);\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.s3Key == null) {\n throw new qq.Error(\"Did not find s3Key property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedKeys[id] = sessionData.s3Key;\n this._cannedBuckets[id] = sessionData.s3Bucket;\n }\n\n return id;\n }\n });\n}());\n","/* globals qq, CryptoJS */\n\n// IE 10 does not support Uint8ClampedArray. We don't need it, but CryptoJS attempts to reference it\n// inside a conditional via an instanceof check, which breaks S3 v4 signatures for chunked uploads.\nif (!window.Uint8ClampedArray) {\n window.Uint8ClampedArray = function() {};\n}\n/**\n * Handles signature determination for HTML Form Upload requests and Multipart Uploader requests (via the S3 REST API).\n *\n * If the S3 requests are to be signed server side, this module will send a POST request to the server in an attempt\n * to solicit signatures for various S3-related requests. This module also parses the response and attempts\n * to determine if the effort was successful.\n *\n * If the S3 requests are to be signed client-side, without the help of a server, this module will utilize CryptoJS to\n * sign the requests directly in the browser and send them off to S3.\n *\n * @param o Options associated with all such requests\n * @returns {{getSignature: Function}} API method used to initiate the signature request.\n * @constructor\n */\nqq.s3.RequestSigner = function(o) {\n \"use strict\";\n\n var requester,\n thisSignatureRequester = this,\n pendingSignatures = {},\n options = {\n expectingPolicy: false,\n method: \"POST\",\n signatureSpec: {\n drift: 0,\n credentialsProvider: {},\n endpoint: null,\n customHeaders: {},\n version: 2\n },\n maxConnections: 3,\n endpointStore: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n },\n credentialsProvider,\n\n generateHeaders = function(signatureConstructor, signature, promise) {\n var headers = signatureConstructor.getHeaders();\n\n if (options.signatureSpec.version === 4) {\n headers.Authorization = qq.s3.util.V4_ALGORITHM_PARAM_VALUE +\n \" Credential=\" + options.signatureSpec.credentialsProvider.get().accessKey + \"/\" +\n qq.s3.util.getCredentialsDate(signatureConstructor.getRequestDate()) + \"/\" +\n options.signatureSpec.region + \"/\" +\n \"s3/aws4_request,\" +\n \"SignedHeaders=\" + signatureConstructor.getSignedHeaders() + \",\" +\n \"Signature=\" + signature;\n }\n else {\n headers.Authorization = \"AWS \" + options.signatureSpec.credentialsProvider.get().accessKey + \":\" + signature;\n }\n\n promise.success(headers, signatureConstructor.getEndOfUrl());\n },\n\n v2 = {\n getStringToSign: function(signatureSpec) {\n return qq.format(\"{}\\n{}\\n{}\\n\\n{}/{}/{}\",\n signatureSpec.method,\n signatureSpec.contentMd5 || \"\",\n signatureSpec.contentType || \"\",\n signatureSpec.headersStr || \"\\n\",\n signatureSpec.bucket,\n signatureSpec.endOfUrl);\n },\n\n signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {\n var headersWordArray = qq.CryptoJS.enc.Utf8.parse(headersStr),\n headersHmacSha1 = qq.CryptoJS.HmacSHA1(headersWordArray, credentialsProvider.get().secretKey),\n headersHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(headersHmacSha1);\n\n generateHeaders(signatureConstructor, headersHmacSha1Base64, signatureEffort);\n },\n\n signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var policyStr = JSON.stringify(policy),\n policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr),\n base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray),\n policyHmacSha1 = qq.CryptoJS.HmacSHA1(base64Policy, credentialsProvider.get().secretKey),\n policyHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(policyHmacSha1);\n\n signatureEffort.success({\n policy: base64Policy,\n signature: policyHmacSha1Base64\n }, updatedAccessKey, updatedSessionToken);\n }\n },\n\n v4 = {\n getCanonicalQueryString: function(endOfUri) {\n var queryParamIdx = endOfUri.indexOf(\"?\"),\n canonicalQueryString = \"\",\n encodedQueryParams, encodedQueryParamNames, queryStrings;\n\n if (queryParamIdx >= 0) {\n encodedQueryParams = {};\n queryStrings = endOfUri.substr(queryParamIdx + 1).split(\"&\");\n\n qq.each(queryStrings, function(idx, queryString) {\n var nameAndVal = queryString.split(\"=\"),\n paramVal = nameAndVal[1];\n\n if (paramVal == null) {\n paramVal = \"\";\n }\n\n encodedQueryParams[encodeURIComponent(nameAndVal[0])] = encodeURIComponent(paramVal);\n });\n\n encodedQueryParamNames = Object.keys(encodedQueryParams).sort();\n encodedQueryParamNames.forEach(function(encodedQueryParamName, idx) {\n canonicalQueryString += encodedQueryParamName + \"=\" + encodedQueryParams[encodedQueryParamName];\n if (idx < encodedQueryParamNames.length - 1) {\n canonicalQueryString += \"&\";\n }\n });\n }\n\n return canonicalQueryString;\n },\n\n getCanonicalRequest: function(signatureSpec) {\n return qq.format(\"{}\\n{}\\n{}\\n{}\\n{}\\n{}\",\n signatureSpec.method,\n v4.getCanonicalUri(signatureSpec.endOfUrl),\n v4.getCanonicalQueryString(signatureSpec.endOfUrl),\n signatureSpec.headersStr || \"\\n\",\n v4.getSignedHeaders(signatureSpec.headerNames),\n signatureSpec.hashedContent);\n },\n\n getCanonicalUri: function(endOfUri) {\n var path = endOfUri,\n queryParamIdx = endOfUri.indexOf(\"?\");\n\n if (queryParamIdx > 0) {\n path = endOfUri.substr(0, queryParamIdx);\n }\n return \"/\" + path;\n },\n\n getEncodedHashedPayload: function(body) {\n var promise = new qq.Promise(),\n reader;\n\n if (qq.isBlob(body)) {\n // TODO hash blob in webworker if this becomes a notable perf issue\n reader = new FileReader();\n reader.onloadend = function(e) {\n if (e.target.readyState === FileReader.DONE) {\n if (e.target.error) {\n promise.failure(e.target.error);\n }\n else {\n var wordArray = qq.CryptoJS.lib.WordArray.create(e.target.result);\n promise.success(qq.CryptoJS.SHA256(wordArray).toString());\n }\n }\n };\n reader.readAsArrayBuffer(body);\n }\n else {\n body = body || \"\";\n promise.success(qq.CryptoJS.SHA256(body).toString());\n }\n\n return promise;\n },\n\n getScope: function(date, region) {\n return qq.s3.util.getCredentialsDate(date) + \"/\" +\n region + \"/s3/aws4_request\";\n },\n\n getStringToSign: function(signatureSpec) {\n var canonicalRequest = v4.getCanonicalRequest(signatureSpec),\n date = qq.s3.util.getV4PolicyDate(signatureSpec.date, signatureSpec.drift),\n hashedRequest = qq.CryptoJS.SHA256(canonicalRequest).toString(),\n scope = v4.getScope(signatureSpec.date, options.signatureSpec.region),\n stringToSignTemplate = \"AWS4-HMAC-SHA256\\n{}\\n{}\\n{}\";\n\n return {\n hashed: qq.format(stringToSignTemplate, date, scope, hashedRequest),\n raw: qq.format(stringToSignTemplate, date, scope, canonicalRequest)\n };\n },\n\n getSignedHeaders: function(headerNames) {\n var signedHeaders = \"\";\n\n headerNames.forEach(function(headerName, idx) {\n signedHeaders += headerName.toLowerCase();\n\n if (idx < headerNames.length - 1) {\n signedHeaders += \";\";\n }\n });\n\n return signedHeaders;\n },\n\n signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {\n var secretKey = credentialsProvider.get().secretKey,\n headersPattern = /.+\\n.+\\n(\\d+)\\/(.+)\\/s3\\/.+\\n(.+)/,\n matches = headersPattern.exec(headersStr),\n dateKey, dateRegionKey, dateRegionServiceKey, signingKey;\n\n dateKey = qq.CryptoJS.HmacSHA256(matches[1], \"AWS4\" + secretKey);\n dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);\n dateRegionServiceKey = qq.CryptoJS.HmacSHA256(\"s3\", dateRegionKey);\n signingKey = qq.CryptoJS.HmacSHA256(\"aws4_request\", dateRegionServiceKey);\n\n generateHeaders(signatureConstructor, qq.CryptoJS.HmacSHA256(headersStr, signingKey), signatureEffort);\n },\n\n signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var policyStr = JSON.stringify(policy),\n policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr),\n base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray),\n secretKey = credentialsProvider.get().secretKey,\n credentialPattern = /.+\\/(.+)\\/(.+)\\/s3\\/aws4_request/,\n credentialCondition = (function() {\n var credential = null;\n qq.each(policy.conditions, function(key, condition) {\n var val = condition[\"x-amz-credential\"];\n if (val) {\n credential = val;\n return false;\n }\n });\n return credential;\n }()),\n matches, dateKey, dateRegionKey, dateRegionServiceKey, signingKey;\n\n matches = credentialPattern.exec(credentialCondition);\n dateKey = qq.CryptoJS.HmacSHA256(matches[1], \"AWS4\" + secretKey);\n dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);\n dateRegionServiceKey = qq.CryptoJS.HmacSHA256(\"s3\", dateRegionKey);\n signingKey = qq.CryptoJS.HmacSHA256(\"aws4_request\", dateRegionServiceKey);\n\n signatureEffort.success({\n policy: base64Policy,\n signature: qq.CryptoJS.HmacSHA256(base64Policy, signingKey).toString()\n }, updatedAccessKey, updatedSessionToken);\n }\n };\n\n qq.extend(options, o, true);\n credentialsProvider = options.signatureSpec.credentialsProvider;\n\n function handleSignatureReceived(id, xhrOrXdr, isError) {\n var responseJson = xhrOrXdr.responseText,\n pendingSignatureData = pendingSignatures[id],\n promise = pendingSignatureData.promise,\n signatureConstructor = pendingSignatureData.signatureConstructor,\n errorMessage, response;\n\n delete pendingSignatures[id];\n\n // Attempt to parse what we would expect to be a JSON response\n if (responseJson) {\n try {\n response = qq.parseJson(responseJson);\n }\n catch (error) {\n options.log(\"Error attempting to parse signature response: \" + error, \"error\");\n }\n }\n\n // If the response is parsable and contains an `error` property, use it as the error message\n if (response && response.error) {\n isError = true;\n errorMessage = response.error;\n }\n // If we have received a parsable response, and it has an `invalid` property,\n // the policy document or request headers may have been tampered with client-side.\n else if (response && response.invalid) {\n isError = true;\n errorMessage = \"Invalid policy document or request headers!\";\n }\n // Make sure the response contains policy & signature properties\n else if (response) {\n if (options.expectingPolicy && !response.policy) {\n isError = true;\n errorMessage = \"Response does not include the base64 encoded policy!\";\n }\n else if (!response.signature) {\n isError = true;\n errorMessage = \"Response does not include the signature!\";\n }\n }\n // Something unknown went wrong\n else {\n isError = true;\n errorMessage = \"Received an empty or invalid response from the server!\";\n }\n\n if (isError) {\n if (errorMessage) {\n options.log(errorMessage, \"error\");\n }\n\n promise.failure(errorMessage);\n }\n else if (signatureConstructor) {\n generateHeaders(signatureConstructor, response.signature, promise);\n }\n else {\n promise.success(response);\n }\n }\n\n function getStringToSignArtifacts(id, version, requestInfo) {\n var promise = new qq.Promise(),\n method = \"POST\",\n headerNames = [],\n headersStr = \"\",\n now = new Date(),\n endOfUrl, signatureSpec, toSign,\n\n generateStringToSign = function(requestInfo) {\n var contentMd5,\n headerIndexesToRemove = [];\n\n qq.each(requestInfo.headers, function(name) {\n headerNames.push(name);\n });\n headerNames.sort();\n\n qq.each(headerNames, function(idx, headerName) {\n if (qq.indexOf(qq.s3.util.UNSIGNABLE_REST_HEADER_NAMES, headerName) < 0) {\n headersStr += headerName.toLowerCase() + \":\" + requestInfo.headers[headerName].trim() + \"\\n\";\n }\n else if (headerName === \"Content-MD5\") {\n contentMd5 = requestInfo.headers[headerName];\n }\n else {\n headerIndexesToRemove.unshift(idx);\n }\n });\n\n qq.each(headerIndexesToRemove, function(idx, headerIdx) {\n headerNames.splice(headerIdx, 1);\n });\n\n signatureSpec = {\n bucket: requestInfo.bucket,\n contentMd5: contentMd5,\n contentType: requestInfo.contentType,\n date: now,\n drift: options.signatureSpec.drift,\n endOfUrl: endOfUrl,\n hashedContent: requestInfo.hashedContent,\n headerNames: headerNames,\n headersStr: headersStr,\n method: method\n };\n\n toSign = version === 2 ? v2.getStringToSign(signatureSpec) : v4.getStringToSign(signatureSpec);\n\n return {\n date: now,\n endOfUrl: endOfUrl,\n signedHeaders: version === 4 ? v4.getSignedHeaders(signatureSpec.headerNames) : null,\n toSign: version === 4 ? toSign.hashed : toSign,\n toSignRaw: version === 4 ? toSign.raw : toSign\n };\n };\n\n /*jshint indent:false */\n switch (requestInfo.type) {\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_ABORT:\n method = \"DELETE\";\n endOfUrl = qq.format(\"uploadId={}\", requestInfo.uploadId);\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_INITIATE:\n endOfUrl = \"uploads\";\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_COMPLETE:\n endOfUrl = qq.format(\"uploadId={}\", requestInfo.uploadId);\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_UPLOAD:\n method = \"PUT\";\n endOfUrl = qq.format(\"partNumber={}&uploadId={}\", requestInfo.partNum, requestInfo.uploadId);\n break;\n }\n\n endOfUrl = requestInfo.key + \"?\" + endOfUrl;\n\n if (version === 4) {\n v4.getEncodedHashedPayload(requestInfo.content).then(function(hashedContent) {\n requestInfo.headers[\"x-amz-content-sha256\"] = hashedContent;\n requestInfo.headers.Host = requestInfo.host;\n requestInfo.headers[\"x-amz-date\"] = qq.s3.util.getV4PolicyDate(now, options.signatureSpec.drift);\n requestInfo.hashedContent = hashedContent;\n\n promise.success(generateStringToSign(requestInfo));\n }, function (err) {\n promise.failure(err);\n });\n }\n else {\n promise.success(generateStringToSign(requestInfo));\n }\n\n return promise;\n }\n\n function determineSignatureClientSide(id, toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var updatedHeaders;\n\n // REST API request\n if (toBeSigned.signatureConstructor) {\n if (updatedSessionToken) {\n updatedHeaders = toBeSigned.signatureConstructor.getHeaders();\n updatedHeaders[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;\n toBeSigned.signatureConstructor.withHeaders(updatedHeaders);\n }\n\n toBeSigned.signatureConstructor.getToSign(id).then(function(signatureArtifacts) {\n signApiRequest(toBeSigned.signatureConstructor, signatureArtifacts.stringToSign, signatureEffort);\n }, function (err) {\n signatureEffort.failure(err);\n });\n }\n // Form upload (w/ policy document)\n else {\n updatedSessionToken && qq.s3.util.refreshPolicyCredentials(toBeSigned, updatedSessionToken);\n signPolicy(toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n }\n\n function signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n if (options.signatureSpec.version === 4) {\n v4.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n else {\n v2.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n }\n\n function signApiRequest(signatureConstructor, headersStr, signatureEffort) {\n if (options.signatureSpec.version === 4) {\n v4.signApiRequest(signatureConstructor, headersStr, signatureEffort);\n }\n else {\n v2.signApiRequest(signatureConstructor, headersStr, signatureEffort);\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n contentType: \"application/json; charset=utf-8\",\n endpointStore: {\n get: function() {\n return options.signatureSpec.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.signatureSpec.customHeaders,\n log: options.log,\n onComplete: handleSignatureReceived,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * On success, an object containing the parsed JSON response will be passed into the success handler if the\n * request succeeds. Otherwise an error message will be passed into the failure method.\n *\n * @param id File ID.\n * @param toBeSigned an Object that holds the item(s) to be signed\n * @returns {qq.Promise} A promise that is fulfilled when the response has been received.\n */\n getSignature: function(id, toBeSigned) {\n var params = toBeSigned,\n signatureConstructor = toBeSigned.signatureConstructor,\n signatureEffort = new qq.Promise(),\n queryParams;\n\n if (options.signatureSpec.version === 4) {\n queryParams = {v4: true};\n }\n\n if (credentialsProvider.get().secretKey && qq.CryptoJS) {\n if (credentialsProvider.get().expiration.getTime() > Date.now()) {\n determineSignatureClientSide(id, toBeSigned, signatureEffort);\n }\n // If credentials are expired, ask for new ones before attempting to sign request\n else {\n credentialsProvider.onExpired().then(function() {\n determineSignatureClientSide(id, toBeSigned,\n signatureEffort,\n credentialsProvider.get().accessKey,\n credentialsProvider.get().sessionToken);\n }, function(errorMsg) {\n options.log(\"Attempt to update expired credentials apparently failed! Unable to sign request. \", \"error\");\n signatureEffort.failure(\"Unable to sign request - expired credentials.\");\n });\n }\n }\n else {\n options.log(\"Submitting S3 signature request for \" + id);\n\n if (signatureConstructor) {\n signatureConstructor.getToSign(id).then(function(signatureArtifacts) {\n params = {headers: signatureArtifacts.stringToSignRaw};\n requester.initTransport(id)\n .withParams(params)\n .withQueryParams(queryParams)\n .send();\n }, function (err) {\n options.log(\"Failed to construct signature. \", \"error\");\n signatureEffort.failure(\"Failed to construct signature.\");\n });\n }\n else {\n requester.initTransport(id)\n .withParams(params)\n .withQueryParams(queryParams)\n .send();\n }\n\n pendingSignatures[id] = {\n promise: signatureEffort,\n signatureConstructor: signatureConstructor\n };\n }\n\n return signatureEffort;\n },\n\n constructStringToSign: function(type, bucket, host, key) {\n var headers = {},\n uploadId, content, contentType, partNum, artifacts;\n\n return {\n withHeaders: function(theHeaders) {\n headers = theHeaders;\n return this;\n },\n\n withUploadId: function(theUploadId) {\n uploadId = theUploadId;\n return this;\n },\n\n withContent: function(theContent) {\n content = theContent;\n return this;\n },\n\n withContentType: function(theContentType) {\n contentType = theContentType;\n return this;\n },\n\n withPartNum: function(thePartNum) {\n partNum = thePartNum;\n return this;\n },\n\n getToSign: function(id) {\n var sessionToken = credentialsProvider.get().sessionToken,\n promise = new qq.Promise(),\n adjustedDate = new Date(Date.now() + options.signatureSpec.drift);\n\n headers[\"x-amz-date\"] = adjustedDate.toUTCString();\n\n if (sessionToken) {\n headers[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n getStringToSignArtifacts(id, options.signatureSpec.version, {\n bucket: bucket,\n content: content,\n contentType: contentType,\n headers: headers,\n host: host,\n key: key,\n partNum: partNum,\n type: type,\n uploadId: uploadId\n }).then(function(_artifacts_) {\n artifacts = _artifacts_;\n promise.success({\n headers: (function() {\n if (contentType) {\n headers[\"Content-Type\"] = contentType;\n }\n\n delete headers.Host; // we don't want this to be set on the XHR-initiated request\n return headers;\n }()),\n date: artifacts.date,\n endOfUrl: artifacts.endOfUrl,\n signedHeaders: artifacts.signedHeaders,\n stringToSign: artifacts.toSign,\n stringToSignRaw: artifacts.toSignRaw\n });\n }, function (err) {\n promise.failure(err);\n });\n\n return promise;\n },\n\n getHeaders: function() {\n return qq.extend({}, headers);\n },\n\n getEndOfUrl: function() {\n return artifacts && artifacts.endOfUrl;\n },\n\n getRequestDate: function() {\n return artifacts && artifacts.date;\n },\n\n getSignedHeaders: function() {\n return artifacts && artifacts.signedHeaders;\n }\n };\n }\n });\n};\n\nqq.s3.RequestSigner.prototype.REQUEST_TYPE = {\n MULTIPART_INITIATE: \"multipart_initiate\",\n MULTIPART_COMPLETE: \"multipart_complete\",\n MULTIPART_ABORT: \"multipart_abort\",\n MULTIPART_UPLOAD: \"multipart_upload\"\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/*globals qq*/\n/**\n * Ajax requester used to send an [\"Initiate Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadInitiate.html)\n * request to S3 via the REST API.\n *\n * @param o Options from the caller - will override the defaults.\n * @constructor\n */\nqq.s3.InitiateMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingInitiateRequests = {},\n options = {\n filenameParam: \"qqfilename\",\n method: \"POST\",\n endpointStore: null,\n paramsStore: null,\n signatureSpec: null,\n aclStore: null,\n reducedRedundancy: false,\n serverSideEncryption: false,\n maxConnections: 3,\n getContentType: function(id) {},\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n getName: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Determine all headers for the \"Initiate MPU\" request, including the \"Authorization\" header, which must be determined\n * by the local server. This is a promissory function. If the server responds with a signature, the headers\n * (including the Authorization header) will be passed into the success method of the promise. Otherwise, the failure\n * method on the promise will be called.\n *\n * @param id Associated file ID\n * @returns {qq.Promise}\n */\n function getHeaders(id) {\n var bucket = options.getBucket(id),\n host = options.getHost(id),\n headers = {},\n promise = new qq.Promise(),\n key = options.getKey(id),\n signatureConstructor;\n\n headers[\"x-amz-acl\"] = options.aclStore.get(id);\n\n if (options.reducedRedundancy) {\n headers[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (options.serverSideEncryption) {\n headers[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n headers[qq.s3.util.AWS_PARAM_PREFIX + options.filenameParam] = encodeURIComponent(options.getName(id));\n\n qq.each(options.paramsStore.get(id), function(name, val) {\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {\n headers[name] = val;\n }\n else {\n headers[qq.s3.util.AWS_PARAM_PREFIX + name] = encodeURIComponent(val);\n }\n });\n\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_INITIATE, bucket, host, key)\n .withContentType(options.getContentType(id))\n .withHeaders(headers);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Initiate MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleInitiateRequestComplete(id, xhr, isError) {\n var promise = pendingInitiateRequests[id],\n domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n uploadIdElements, messageElements, uploadId, errorMessage, status;\n\n delete pendingInitiateRequests[id];\n\n // The base ajax requester may declare the request to be a failure based on status code.\n if (isError) {\n status = xhr.status;\n\n messageElements = responseDoc.getElementsByTagName(\"Message\");\n if (messageElements.length > 0) {\n errorMessage = messageElements[0].textContent;\n }\n }\n // If the base ajax requester has not declared this a failure, make sure we can retrieve the uploadId from the response.\n else {\n uploadIdElements = responseDoc.getElementsByTagName(\"UploadId\");\n if (uploadIdElements.length > 0) {\n uploadId = uploadIdElements[0].textContent;\n }\n else {\n errorMessage = \"Upload ID missing from request\";\n }\n }\n\n // Either fail the promise (passing a descriptive error message) or declare it a success (passing the upload ID)\n if (uploadId === undefined) {\n if (errorMessage) {\n options.log(qq.format(\"Specific problem detected initiating multipart upload request for {}: '{}'.\", id, errorMessage), \"error\");\n }\n else {\n options.log(qq.format(\"Unexplained error with initiate multipart upload request for {}. Status code {}.\", id, status), \"error\");\n }\n\n promise.failure(\"Problem initiating upload request.\", xhr);\n }\n else {\n options.log(qq.format(\"Initiate multipart upload request successful for {}. Upload ID is {}\", id, uploadId));\n promise.success(uploadId, xhr);\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n method: options.method,\n contentType: null,\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleInitiateRequestComplete,\n successfulResponseCodes: {\n POST: [200]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Initiate MPU\" request to AWS via the REST API. First, though, we must get a signature from the\n * local server for the request. If all is successful, the uploadId from AWS will be passed into the promise's\n * success handler. Otherwise, an error message will ultimately be passed into the failure method.\n *\n * @param id The ID associated with the file\n * @returns {qq.Promise}\n */\n send: function(id) {\n var promise = new qq.Promise();\n\n getHeaders(id).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 initiate multipart upload request for \" + id);\n\n pendingInitiateRequests[id] = promise;\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .send();\n }, promise.failure);\n\n return promise;\n }\n });\n};\n","/*globals qq*/\n/**\n * Ajax requester used to send an [\"Complete Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadComplete.html)\n * request to S3 via the REST API.\n *\n * @param o Options passed by the creator, to overwrite any default option values.\n * @constructor\n */\nqq.s3.CompleteMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingCompleteRequests = {},\n options = {\n method: \"POST\",\n contentType: \"text/xml\",\n endpointStore: null,\n signatureSpec: null,\n maxConnections: 3,\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n // Transport for requesting signatures (for the \"Complete\" requests) from the local server\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Attach all required headers (including Authorization) to the \"Complete\" request. This is a promissory function\n * that will fulfill the associated promise once all headers have been attached or when an error has occurred that\n * prevents headers from being attached.\n *\n * @returns {qq.Promise}\n */\n function getHeaders(id, uploadId, body) {\n var headers = {},\n promise = new qq.Promise(),\n bucket = options.getBucket(id),\n host = options.getHost(id),\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_COMPLETE, bucket, host, options.getKey(id))\n .withUploadId(uploadId)\n .withContent(body)\n .withContentType(\"application/xml; charset=UTF-8\");\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Complete MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleCompleteRequestComplete(id, xhr, isError) {\n var promise = pendingCompleteRequests[id],\n domParser = new DOMParser(),\n bucket = options.getBucket(id),\n key = options.getKey(id),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n bucketEls = responseDoc.getElementsByTagName(\"Bucket\"),\n keyEls = responseDoc.getElementsByTagName(\"Key\");\n\n delete pendingCompleteRequests[id];\n\n options.log(qq.format(\"Complete response status {}, body = {}\", xhr.status, xhr.responseText));\n\n // If the base requester has determine this a failure, give up.\n if (isError) {\n options.log(qq.format(\"Complete Multipart Upload request for {} failed with status {}.\", id, xhr.status), \"error\");\n }\n else {\n // Make sure the correct bucket and key has been specified in the XML response from AWS.\n if (bucketEls.length && keyEls.length) {\n if (bucketEls[0].textContent !== bucket) {\n isError = true;\n options.log(qq.format(\"Wrong bucket in response to Complete Multipart Upload request for {}.\", id), \"error\");\n }\n\n // TODO Compare key name from response w/ expected key name if AWS ever fixes the encoding of key names in this response.\n }\n else {\n isError = true;\n options.log(qq.format(\"Missing bucket and/or key in response to Complete Multipart Upload request for {}.\", id), \"error\");\n }\n }\n\n if (isError) {\n promise.failure(\"Problem combining the file parts!\", xhr);\n }\n else {\n promise.success({}, xhr);\n }\n }\n\n /**\n * @param etagEntries Array of objects containing `etag` values and their associated `part` numbers.\n * @returns {string} XML string containing the body to send with the \"Complete\" request\n */\n function getCompleteRequestBody(etagEntries) {\n var doc = document.implementation.createDocument(null, \"CompleteMultipartUpload\", null);\n\n // The entries MUST be sorted by part number, per the AWS API spec.\n etagEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(etagEntries, function(idx, etagEntry) {\n var part = etagEntry.part,\n etag = etagEntry.etag,\n partEl = doc.createElement(\"Part\"),\n partNumEl = doc.createElement(\"PartNumber\"),\n partNumTextEl = doc.createTextNode(part),\n etagTextEl = doc.createTextNode(etag),\n etagEl = doc.createElement(\"ETag\");\n\n etagEl.appendChild(etagTextEl);\n partNumEl.appendChild(partNumTextEl);\n partEl.appendChild(partNumEl);\n partEl.appendChild(etagEl);\n qq(doc).children()[0].appendChild(partEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n method: options.method,\n contentType: \"application/xml; charset=UTF-8\",\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleCompleteRequestComplete,\n successfulResponseCodes: {\n POST: [200]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Complete\" request and fulfills the returned promise when the success of this request is known.\n *\n * @param id ID associated with the file.\n * @param uploadId AWS uploadId for this file\n * @param etagEntries Array of objects containing `etag` values and their associated `part` numbers.\n * @returns {qq.Promise}\n */\n send: function(id, uploadId, etagEntries) {\n var promise = new qq.Promise(),\n body = getCompleteRequestBody(etagEntries);\n\n getHeaders(id, uploadId, body).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 complete multipart upload request for \" + id);\n\n pendingCompleteRequests[id] = promise;\n delete headers[\"Content-Type\"];\n\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .withPayload(body)\n .send();\n }, promise.failure);\n\n return promise;\n }\n });\n};\n","/*globals qq */\n/**\n * Ajax requester used to send an [\"Abort Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadAbort.html)\n * request to S3 via the REST API.\n\n * @param o\n * @constructor\n */\nqq.s3.AbortMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n endpointStore: null,\n signatureSpec: null,\n maxConnections: 3,\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n // Transport for requesting signatures (for the \"Complete\" requests) from the local server\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Attach all required headers (including Authorization) to the \"Abort\" request. This is a promissory function\n * that will fulfill the associated promise once all headers have been attached or when an error has occurred that\n * prevents headers from being attached.\n *\n * @param id Associated file ID\n * @param uploadId ID of the associated upload, according to AWS\n * @returns {qq.Promise}\n */\n function getHeaders(id, uploadId) {\n var headers = {},\n promise = new qq.Promise(),\n bucket = options.getBucket(id),\n host = options.getHost(id),\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, options.getKey(id))\n .withUploadId(uploadId);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Abort MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleAbortRequestComplete(id, xhr, isError) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n errorEls = responseDoc.getElementsByTagName(\"Error\"),\n awsErrorMsg;\n\n options.log(qq.format(\"Abort response status {}, body = {}\", xhr.status, xhr.responseText));\n\n // If the base requester has determine this a failure, give up.\n if (isError) {\n options.log(qq.format(\"Abort Multipart Upload request for {} failed with status {}.\", id, xhr.status), \"error\");\n }\n else {\n // Make sure the correct bucket and key has been specified in the XML response from AWS.\n if (errorEls.length) {\n isError = true;\n awsErrorMsg = responseDoc.getElementsByTagName(\"Message\")[0].textContent;\n options.log(qq.format(\"Failed to Abort Multipart Upload request for {}. Error: {}\", id, awsErrorMsg), \"error\");\n }\n else {\n options.log(qq.format(\"Abort MPU request succeeded for file ID {}.\", id));\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [\"DELETE\"],\n method: options.method,\n contentType: null,\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleAbortRequestComplete,\n successfulResponseCodes: {\n DELETE: [204]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Abort\" request.\n *\n * @param id ID associated with the file.\n * @param uploadId AWS uploadId for this file\n */\n send: function(id, uploadId) {\n getHeaders(id, uploadId).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 Abort multipart upload request for \" + id);\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .send();\n });\n }\n });\n};\n","/*globals qq */\n/**\n * Upload handler used by the upload to S3 module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to S3 buckets via the associated AWS API.\n *\n * If chunking is supported and enabled, the S3 Multipart Upload REST API is utilized.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.s3.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var getName = proxy.getName,\n log = proxy.log,\n clockDrift = spec.clockDrift,\n expectedStatus = 200,\n onGetBucket = spec.getBucket,\n onGetHost = spec.getHost,\n onGetKeyName = spec.getKeyName,\n filenameParam = spec.filenameParam,\n paramsStore = spec.paramsStore,\n endpointStore = spec.endpointStore,\n aclStore = spec.aclStore,\n reducedRedundancy = spec.objectProperties.reducedRedundancy,\n region = spec.objectProperties.region,\n serverSideEncryption = spec.objectProperties.serverSideEncryption,\n validation = spec.validation,\n signature = qq.extend({region: region, drift: clockDrift}, spec.signature),\n handler = this,\n credentialsProvider = spec.signature.credentialsProvider,\n\n chunked = {\n // Sends a \"Complete Multipart Upload\" request and then signals completion of the upload\n // when the response to this request has been parsed.\n combine: function(id) {\n var uploadId = handler._getPersistableData(id).uploadId,\n etagMap = handler._getPersistableData(id).etags,\n result = new qq.Promise();\n\n requesters.completeMultipart.send(id, uploadId, etagMap).then(\n result.success,\n\n function failure(reason, xhr) {\n result.failure(upload.done(id, xhr).response, xhr);\n }\n );\n\n return result;\n },\n\n // The last step in handling a chunked upload. This is called after each chunk has been sent.\n // The request may be successful, or not. If it was successful, we must extract the \"ETag\" element\n // in the XML response and store that along with the associated part number.\n // We need these items to \"Complete\" the multipart upload after all chunks have been successfully sent.\n done: function(id, xhr, chunkIdx) {\n var response = upload.response.parse(id, xhr),\n etag;\n\n if (response.success) {\n etag = xhr.getResponseHeader(\"ETag\");\n\n if (!handler._getPersistableData(id).etags) {\n handler._getPersistableData(id).etags = [];\n }\n handler._getPersistableData(id).etags.push({part: chunkIdx + 1, etag: etag});\n }\n },\n\n /**\n * Determines headers that must be attached to the chunked (Multipart Upload) request. One of these headers is an\n * Authorization value, which must be determined by asking the local server to sign the request first. So, this\n * function returns a promise. Once all headers are determined, the `success` method of the promise is called with\n * the headers object. If there was some problem determining the headers, we delegate to the caller's `failure`\n * callback.\n *\n * @param id File ID\n * @param chunkIdx Index of the chunk to PUT\n * @returns {qq.Promise}\n */\n initHeaders: function(id, chunkIdx, blob) {\n var headers = {},\n bucket = upload.bucket.getName(id),\n host = upload.host.getName(id),\n key = upload.key.urlSafe(id),\n promise = new qq.Promise(),\n signatureConstructor = requesters.restSignature.constructStringToSign\n (requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key)\n .withPartNum(chunkIdx + 1)\n .withContent(blob)\n .withUploadId(handler._getPersistableData(id).uploadId);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n requesters.restSignature.getSignature(id + \".\" + chunkIdx, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n },\n\n put: function(id, chunkIdx) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx),\n domain = spec.endpointStore.get(id),\n promise = new qq.Promise();\n\n // Add appropriate headers to the multipart upload request.\n // Once these have been determined (asynchronously) attach the headers and send the chunk.\n chunked.initHeaders(id, chunkIdx, chunkData.blob).then(function(headers, endOfUrl) {\n if (xhr._cancelled) {\n log(qq.format(\"Upload of item {}.{} cancelled. Upload will not start after successful signature request.\", id, chunkIdx));\n promise.failure({error: \"Chunk upload cancelled\"});\n }\n else {\n var url = domain + \"/\" + endOfUrl;\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n upload.track(id, xhr, chunkIdx).then(promise.success, promise.failure);\n xhr.open(\"PUT\", url, true);\n\n qq.each(headers, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n\n xhr.send(chunkData.blob);\n }\n }, function() {\n promise.failure({error: \"Problem signing the chunk!\"}, xhr);\n });\n\n return promise;\n },\n\n send: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n chunked.setup(id).then(\n // The \"Initiate\" request succeeded. We are ready to send the first chunk.\n function() {\n chunked.put(id, chunkIdx).then(promise.success, promise.failure);\n },\n\n // We were unable to initiate the chunked upload process.\n function(errorMessage, xhr) {\n promise.failure({error: errorMessage}, xhr);\n }\n );\n\n return promise;\n },\n\n /**\n * Sends an \"Initiate Multipart Upload\" request to S3 via the REST API, but only if the MPU has not already been\n * initiated.\n *\n * @param id Associated file ID\n * @returns {qq.Promise} A promise that is fulfilled when the initiate request has been sent and the response has been parsed.\n */\n setup: function(id) {\n var promise = new qq.Promise(),\n uploadId = handler._getPersistableData(id).uploadId,\n uploadIdPromise = new qq.Promise();\n\n if (!uploadId) {\n handler._getPersistableData(id).uploadId = uploadIdPromise;\n requesters.initiateMultipart.send(id).then(\n function(uploadId) {\n handler._getPersistableData(id).uploadId = uploadId;\n uploadIdPromise.success(uploadId);\n promise.success(uploadId);\n },\n function(errorMsg, xhr) {\n handler._getPersistableData(id).uploadId = null;\n promise.failure(errorMsg, xhr);\n uploadIdPromise.failure(errorMsg, xhr);\n }\n );\n }\n else if (uploadId instanceof qq.Promise) {\n uploadId.then(function(uploadId) {\n promise.success(uploadId);\n });\n }\n else {\n promise.success(uploadId);\n }\n\n return promise;\n }\n },\n\n requesters = {\n abortMultipart: new qq.s3.AbortMultipartAjaxRequester({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log,\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n }\n }),\n\n completeMultipart: new qq.s3.CompleteMultipartAjaxRequester({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log,\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n }\n }),\n\n initiateMultipart: new qq.s3.InitiateMultipartAjaxRequester({\n filenameParam: filenameParam,\n endpointStore: endpointStore,\n paramsStore: paramsStore,\n signatureSpec: signature,\n aclStore: aclStore,\n reducedRedundancy: reducedRedundancy,\n serverSideEncryption: serverSideEncryption,\n cors: spec.cors,\n log: log,\n getContentType: function(id) {\n return handler._getMimeType(id);\n },\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n },\n getName: function(id) {\n return getName(id);\n }\n }),\n\n policySignature: new qq.s3.RequestSigner({\n expectingPolicy: true,\n signatureSpec: signature,\n cors: spec.cors,\n log: log\n }),\n\n restSignature: new qq.s3.RequestSigner({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log\n })\n },\n\n simple = {\n /**\n * Used for simple (non-chunked) uploads to determine the parameters to send along with the request. Part of this\n * process involves asking the local server to sign the request, so this function returns a promise. The promise\n * is fulfilled when all parameters are determined, or when we determine that all parameters cannot be calculated\n * due to some error.\n *\n * @param id File ID\n * @returns {qq.Promise}\n */\n initParams: function(id) {\n /*jshint -W040 */\n var customParams = paramsStore.get(id);\n customParams[filenameParam] = getName(id);\n\n return qq.s3.util.generateAwsParams({\n endpoint: endpointStore.get(id),\n clockDrift: clockDrift,\n params: customParams,\n type: handler._getMimeType(id),\n bucket: upload.bucket.getName(id),\n key: handler.getThirdPartyFileId(id),\n accessKey: credentialsProvider.get().accessKey,\n sessionToken: credentialsProvider.get().sessionToken,\n acl: aclStore.get(id),\n expectedStatus: expectedStatus,\n minFileSize: validation.minSizeLimit,\n maxFileSize: validation.maxSizeLimit,\n reducedRedundancy: reducedRedundancy,\n region: region,\n serverSideEncryption: serverSideEncryption,\n signatureVersion: signature.version,\n log: log\n },\n qq.bind(requesters.policySignature.getSignature, this, id));\n },\n\n send: function(id) {\n var promise = new qq.Promise(),\n xhr = handler._createXhr(id),\n fileOrBlob = handler.getFile(id);\n\n handler._registerProgressHandler(id);\n upload.track(id, xhr).then(promise.success, promise.failure);\n\n // Delegate to a function the sets up the XHR request and notifies us when it is ready to be sent, along w/ the payload.\n simple.setup(id, xhr, fileOrBlob).then(function(toSend) {\n log(\"Sending upload request for \" + id);\n xhr.send(toSend);\n }, promise.failure);\n\n return promise;\n },\n\n /**\n * Starts the upload process by delegating to an async function that determine parameters to be attached to the\n * request. If all params can be determined, we are called back with the params and the caller of this function is\n * informed by invoking the `success` method on the promise returned by this function, passing the payload of the\n * request. If some error occurs here, we delegate to a function that signals a failure for this upload attempt.\n *\n * Note that this is only used by the simple (non-chunked) upload process.\n *\n * @param id File ID\n * @param xhr XMLHttpRequest to use for the upload\n * @param fileOrBlob `File` or `Blob` to send\n * @returns {qq.Promise}\n */\n setup: function(id, xhr, fileOrBlob) {\n var formData = new FormData(),\n endpoint = endpointStore.get(id),\n url = endpoint,\n promise = new qq.Promise();\n\n simple.initParams(id).then(\n // Success - all params determined\n function(awsParams) {\n xhr.open(\"POST\", url, true);\n\n qq.obj2FormData(awsParams, formData);\n\n // AWS requires the file field be named \"file\".\n formData.append(\"file\", fileOrBlob);\n\n promise.success(formData);\n },\n\n // Failure - we couldn't determine some params (likely the signature)\n function(errorMessage) {\n promise.failure({error: errorMessage});\n }\n );\n\n return promise;\n }\n },\n\n upload = {\n /**\n * Note that this is called when an upload has reached a termination point,\n * regardless of success/failure. For example, it is called when we have\n * encountered an error during the upload or when the file may have uploaded successfully.\n *\n * @param id file ID\n */\n bucket: {\n promise: function(id) {\n var promise = new qq.Promise(),\n cachedBucket = handler._getFileState(id).bucket;\n\n if (cachedBucket) {\n promise.success(cachedBucket);\n }\n else {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n promise.success(bucket);\n }, promise.failure);\n }\n\n return promise;\n },\n\n getName: function(id) {\n return handler._getFileState(id).bucket;\n }\n },\n\n host: {\n promise: function(id) {\n var promise = new qq.Promise(),\n cachedHost = handler._getFileState(id).host;\n\n if (cachedHost) {\n promise.success(cachedHost);\n }\n else {\n onGetHost(id).then(function(host) {\n handler._getFileState(id).host = host;\n promise.success(host);\n }, promise.failure);\n }\n\n return promise;\n },\n\n getName: function(id) {\n return handler._getFileState(id).host;\n }\n },\n\n done: function(id, xhr) {\n var response = upload.response.parse(id, xhr),\n isError = response.success !== true;\n\n if (isError && upload.response.shouldReset(response.code)) {\n log(\"This is an unrecoverable error, we must restart the upload entirely on the next retry attempt.\", \"error\");\n response.reset = true;\n }\n\n return {\n success: !isError,\n response: response\n };\n },\n\n key: {\n promise: function(id) {\n var promise = new qq.Promise(),\n key = handler.getThirdPartyFileId(id);\n\n /* jshint eqnull:true */\n if (key == null) {\n handler._setThirdPartyFileId(id, promise);\n onGetKeyName(id, getName(id)).then(\n function(keyName) {\n handler._setThirdPartyFileId(id, keyName);\n promise.success(keyName);\n },\n function(errorReason) {\n handler._setThirdPartyFileId(id, null);\n promise.failure(errorReason);\n }\n );\n }\n else if (qq.isGenericPromise(key)) {\n key.then(promise.success, promise.failure);\n }\n else {\n promise.success(key);\n }\n\n return promise;\n },\n\n urlSafe: function(id) {\n var encodedKey = handler.getThirdPartyFileId(id);\n return qq.s3.util.uriEscapePath(encodedKey);\n }\n },\n\n response: {\n parse: function(id, xhr) {\n var response = {},\n parsedErrorProps;\n\n try {\n log(qq.format(\"Received response status {} with body: {}\", xhr.status, xhr.responseText));\n\n if (xhr.status === expectedStatus) {\n response.success = true;\n }\n else {\n parsedErrorProps = upload.response.parseError(xhr.responseText);\n\n if (parsedErrorProps) {\n response.error = parsedErrorProps.message;\n response.code = parsedErrorProps.code;\n }\n }\n }\n catch (error) {\n log(\"Error when attempting to parse xhr response text (\" + error.message + \")\", \"error\");\n }\n\n return response;\n },\n\n /**\n * This parses an XML response by extracting the \"Message\" and \"Code\" elements that accompany AWS error responses.\n *\n * @param awsResponseXml XML response from AWS\n * @returns {object} Object w/ `code` and `message` properties, or undefined if we couldn't find error info in the XML document.\n */\n parseError: function(awsResponseXml) {\n var parser = new DOMParser(),\n parsedDoc = parser.parseFromString(awsResponseXml, \"application/xml\"),\n errorEls = parsedDoc.getElementsByTagName(\"Error\"),\n errorDetails = {},\n codeEls, messageEls;\n\n if (errorEls.length) {\n codeEls = parsedDoc.getElementsByTagName(\"Code\");\n messageEls = parsedDoc.getElementsByTagName(\"Message\");\n\n if (messageEls.length) {\n errorDetails.message = messageEls[0].textContent;\n }\n\n if (codeEls.length) {\n errorDetails.code = codeEls[0].textContent;\n }\n\n return errorDetails;\n }\n },\n\n // Determine if the upload should be restarted on the next retry attempt\n // based on the error code returned in the response from AWS.\n shouldReset: function(errorCode) {\n /*jshint -W014 */\n return errorCode === \"EntityTooSmall\"\n || errorCode === \"InvalidPart\"\n || errorCode === \"InvalidPartOrder\"\n || errorCode === \"NoSuchUpload\";\n }\n },\n\n start: function(id, optChunkIdx) {\n var promise = new qq.Promise();\n\n upload.key.promise(id).then(function() {\n upload.bucket.promise(id).then(function() {\n upload.host.promise(id).then(function() {\n /* jshint eqnull:true */\n if (optChunkIdx == null) {\n simple.send(id).then(promise.success, promise.failure);\n }\n else {\n chunked.send(id, optChunkIdx).then(promise.success, promise.failure);\n }\n });\n });\n },\n function(errorReason) {\n promise.failure({error: errorReason});\n });\n\n return promise;\n },\n\n track: function(id, xhr, optChunkIdx) {\n var promise = new qq.Promise();\n\n xhr.onreadystatechange = function() {\n if (xhr.readyState === 4) {\n var result;\n\n /* jshint eqnull:true */\n if (optChunkIdx == null) {\n result = upload.done(id, xhr);\n promise[result.success ? \"success\" : \"failure\"](result.response, xhr);\n }\n else {\n chunked.done(id, xhr, optChunkIdx);\n result = upload.done(id, xhr);\n promise[result.success ? \"success\" : \"failure\"](result.response, xhr);\n }\n }\n };\n\n return promise;\n }\n };\n\n qq.extend(this, {\n uploadChunk: upload.start,\n uploadFile: upload.start\n });\n\n qq.extend(this, new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"s3\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var uploadId = handler._getPersistableData(id) && handler._getPersistableData(id).uploadId,\n existedInLocalStorage = handler._maybeDeletePersistedChunkData(id);\n\n if (uploadId !== undefined && existedInLocalStorage) {\n requesters.abortMultipart.send(id, uploadId);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return chunked.combine(id);\n },\n\n _getLocalStorageId: function(id) {\n var baseStorageId = super_._getLocalStorageId(id),\n bucketName = upload.bucket.getName(id);\n\n return baseStorageId + \"-\" + bucketName;\n }\n };\n });\n};\n","/*globals qq */\n/**\n * Upload handler used by the upload to S3 module that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to S3 buckets via the associated\n * AWS API.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.s3.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n clockDrift = options.clockDrift,\n onUuidChanged = proxy.onUuidChanged,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n onGetBucket = options.getBucket,\n onGetKeyName = options.getKeyName,\n filenameParam = options.filenameParam,\n paramsStore = options.paramsStore,\n endpointStore = options.endpointStore,\n aclStore = options.aclStore,\n reducedRedundancy = options.objectProperties.reducedRedundancy,\n region = options.objectProperties.region,\n serverSideEncryption = options.objectProperties.serverSideEncryption,\n validation = options.validation,\n signature = options.signature,\n successRedirectUrl = options.iframeSupport.localBlankPagePath,\n credentialsProvider = options.signature.credentialsProvider,\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n signatureSpec: signature,\n cors: options.cors,\n log: log\n });\n\n if (successRedirectUrl === undefined) {\n throw new Error(\"successRedirectEndpoint MUST be defined if you intend to use browsers that do not support the File API!\");\n }\n\n /**\n * Attempt to parse the contents of an iframe after receiving a response from the server. If the contents cannot be\n * read (perhaps due to a security error) it is safe to assume that the upload was not successful since Amazon should\n * have redirected to a known endpoint that should provide a parseable response.\n *\n * @param id ID of the associated file\n * @param iframe target of the form submit\n * @returns {boolean} true if the contents can be read, false otherwise\n */\n function isValidResponse(id, iframe) {\n var response,\n endpoint = options.endpointStore.get(id),\n bucket = handler._getFileState(id).bucket,\n doc,\n innerHtml,\n responseData;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n responseData = qq.s3.util.parseIframeResponse(iframe);\n if (responseData.bucket === bucket &&\n responseData.key === qq.s3.util.encodeQueryStringParam(handler.getThirdPartyFileId(id))) {\n\n return true;\n }\n\n log(\"Response from AWS included an unexpected bucket or key name.\", \"error\");\n\n }\n catch (error) {\n log(\"Error when attempting to parse form upload response (\" + error.message + \")\", \"error\");\n }\n\n return false;\n }\n\n function generateAwsParams(id) {\n /*jshint -W040 */\n var customParams = paramsStore.get(id);\n\n customParams[filenameParam] = getName(id);\n\n return qq.s3.util.generateAwsParams({\n endpoint: endpointStore.get(id),\n clockDrift: clockDrift,\n params: customParams,\n bucket: handler._getFileState(id).bucket,\n key: handler.getThirdPartyFileId(id),\n accessKey: credentialsProvider.get().accessKey,\n sessionToken: credentialsProvider.get().sessionToken,\n acl: aclStore.get(id),\n minFileSize: validation.minSizeLimit,\n maxFileSize: validation.maxSizeLimit,\n successRedirectUrl: successRedirectUrl,\n reducedRedundancy: reducedRedundancy,\n region: region,\n serverSideEncryption: serverSideEncryption,\n signatureVersion: signature.version,\n log: log\n },\n qq.bind(getSignatureAjaxRequester.getSignature, this, id));\n }\n\n /**\n * Creates form, that will be submitted to iframe\n */\n function createForm(id, iframe) {\n var promise = new qq.Promise(),\n method = \"POST\",\n endpoint = options.endpointStore.get(id),\n fileName = getName(id);\n\n generateAwsParams(id).then(function(params) {\n var form = handler._initFormForUpload({\n method: method,\n endpoint: endpoint,\n params: params,\n paramsInBody: true,\n targetName: iframe.name\n });\n\n promise.success(form);\n }, function(errorMessage) {\n promise.failure(errorMessage);\n handleFinishedUpload(id, iframe, fileName, {error: errorMessage});\n });\n\n return promise;\n }\n\n function handleUpload(id) {\n var iframe = handler._createIframe(id),\n input = handler.getInput(id),\n promise = new qq.Promise();\n\n createForm(id, iframe).then(function(form) {\n form.appendChild(input);\n\n // Register a callback when the response comes in from S3\n handler._attachLoadEvent(iframe, function(response) {\n log(\"iframe loaded\");\n\n // If the common response handler has determined success or failure immediately\n if (response) {\n // If there is something fundamentally wrong with the response (such as iframe content is not accessible)\n if (response.success === false) {\n log(\"Amazon likely rejected the upload request\", \"error\");\n promise.failure(response);\n }\n }\n // The generic response (iframe onload) handler was not able to make a determination regarding the success of the request\n else {\n response = {};\n response.success = isValidResponse(id, iframe);\n\n // If the more specific response handle detected a problem with the response from S3\n if (response.success === false) {\n log(\"A success response was received by Amazon, but it was invalid in some way.\", \"error\");\n promise.failure(response);\n }\n else {\n qq.extend(response, qq.s3.util.parseIframeResponse(iframe));\n promise.success(response);\n }\n }\n\n handleFinishedUpload(id, iframe);\n });\n\n log(\"Sending upload request for \" + id);\n form.submit();\n qq(form).remove();\n }, promise.failure);\n\n return promise;\n }\n\n function handleFinishedUpload(id, iframe) {\n handler._detachLoadEvent(id);\n iframe && qq(iframe).remove();\n }\n\n qq.extend(this, new qq.FormUploadHandler({\n options: {\n isCors: false,\n inputName: \"file\"\n },\n\n proxy: {\n onCancel: options.onCancel,\n onUuidChanged: onUuidChanged,\n getName: getName,\n getUuid: getUuid,\n log: log\n }\n }));\n\n qq.extend(this, {\n uploadFile: function(id) {\n var name = getName(id),\n promise = new qq.Promise();\n\n if (handler.getThirdPartyFileId(id)) {\n if (handler._getFileState(id).bucket) {\n handleUpload(id).then(promise.success, promise.failure);\n }\n else {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n handleUpload(id).then(promise.success, promise.failure);\n });\n }\n }\n else {\n // The S3 uploader module will either calculate the key or ask the server for it\n // and will call us back once it is known.\n onGetKeyName(id, name).then(function(key) {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n handler._setThirdPartyFileId(id, key);\n handleUpload(id).then(promise.success, promise.failure);\n }, function(errorReason) {\n promise.failure({error: errorReason});\n });\n }, function(errorReason) {\n promise.failure({error: errorReason});\n });\n }\n\n return promise;\n }\n });\n};\n","/*globals qq */\n/**\n * This defines FineUploader mode w/ support for uploading to S3, which provides all the basic\n * functionality of Fine Uploader as well as code to handle uploads directly to S3.\n * This module inherits all logic from FineUploader mode and FineUploaderBasicS3 mode and adds some UI-related logic\n * specific to the upload-to-S3 workflow. Some inherited options and API methods have a special meaning\n * in the context of the S3 uploader.\n */\n(function() {\n \"use strict\";\n\n qq.s3.FineUploader = function(o) {\n var options = {\n failedUploadTextDisplay: {\n mode: \"custom\"\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Inherit instance data from FineUploader, which should in turn inherit from s3.FineUploaderBasic.\n qq.FineUploader.call(this, options, \"s3\");\n\n if (!qq.supportedFeatures.ajaxUploading && options.iframeSupport.localBlankPagePath === undefined) {\n this._options.element.innerHTML = \"You MUST set the localBlankPagePath
property \" +\n \"of the iframeSupport
option since this browser does not support the File API!
\";\n }\n };\n\n // Inherit the API methods from FineUploaderBasicS3\n qq.extend(qq.s3.FineUploader.prototype, qq.s3.FineUploaderBasic.prototype);\n\n // Inherit public and private API methods related to UI\n qq.extend(qq.s3.FineUploader.prototype, qq.uiPublicApi);\n qq.extend(qq.s3.FineUploader.prototype, qq.uiPrivateApi);\n}());\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n","/*globals qq */\n/**\n * This defines FineUploader mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader as well as code to handle uploads directly to Azure.\n * This module inherits all logic from UI & core mode and adds some UI-related logic\n * specific to the upload-to-Azure workflow. Some inherited options and API methods have a special meaning\n * in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploader = function(o) {\n var options = {\n failedUploadTextDisplay: {\n mode: \"custom\"\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Inherit instance data from FineUploader, which should in turn inherit from azure.FineUploaderBasic.\n qq.FineUploader.call(this, options, \"azure\");\n };\n\n // Inherit the API methods from FineUploaderBasicS3\n qq.extend(qq.azure.FineUploader.prototype, qq.azure.FineUploaderBasic.prototype);\n\n // Inherit public and private API methods related to UI\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPublicApi);\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploader.prototype, {\n });\n}());\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.min.js b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.min.js
new file mode 100644
index 000000000000..0c79bedacc20
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.min.js
@@ -0,0 +1,9 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+!function(global){var qq=function(e){"use strict";return{hide:function(){return e.style.display="none",this},attach:function(t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n),function(){qq(e).detach(t,n)}},detach:function(t,n){return e.removeEventListener?e.removeEventListener(t,n,!1):e.attachEvent&&e.detachEvent("on"+t,n),this},contains:function(t){return!!t&&(e===t||(e.contains?e.contains(t):!!(8&t.compareDocumentPosition(e))))},insertBefore:function(t){return t.parentNode.insertBefore(e,t),this},remove:function(){return e.parentNode.removeChild(e),this},css:function(t){if(null==e.style)throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");return null!=t.opacity&&"string"!=typeof e.style.opacity&&"undefined"!=typeof e.filters&&(t.filter="alpha(opacity="+Math.round(100*t.opacity)+")"),qq.extend(e.style,t),this},hasClass:function(t,n){var i=new RegExp("(^| )"+t+"( |$)");return i.test(e.className)||!(!n||!i.test(e.parentNode.className))},addClass:function(t){return qq(e).hasClass(t)||(e.className+=" "+t),this},removeClass:function(t){var n=new RegExp("(^| )"+t+"( |$)");return e.className=e.className.replace(n," ").replace(/^\s+|\s+$/g,""),this},getByClass:function(t,n){var i,o=[];return n&&e.querySelector?e.querySelector("."+t):e.querySelectorAll?e.querySelectorAll("."+t):(i=e.getElementsByTagName("*"),qq.each(i,function(e,n){qq(n).hasClass(t)&&o.push(n)}),n?o[0]:o)},getFirstByClass:function(t){return qq(e).getByClass(t,!0)},children:function(){for(var t=[],n=e.firstChild;n;)1===n.nodeType&&t.push(n),n=n.nextSibling;return t},setText:function(t){return e.innerText=t,e.textContent=t,this},clearText:function(){return qq(e).setText("")},hasAttribute:function(t){var n;return e.hasAttribute?!!e.hasAttribute(t)&&null==/^false$/i.exec(e.getAttribute(t)):(n=e[t],void 0!==n&&null==/^false$/i.exec(n))}}};!function(){"use strict";qq.canvasToBlob=function(e,t,n){return qq.dataUriToBlob(e.toDataURL(t,n))},qq.dataUriToBlob=function(e){var t,n,i,o,r=function(e,t){var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})};return n=e.split(",")[0].indexOf("base64")>=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),o=e.split(",")[0].split(":")[1].split(";")[0],t=new ArrayBuffer(n.length),i=new Uint8Array(t),qq.each(n,function(e,t){i[e]=t.charCodeAt(0)}),r(t,o)},qq.log=function(e,t){window.console&&(t&&"info"!==t?window.console[t]?window.console[t](e):window.console.log("<"+t+"> "+e):window.console.log(e))},qq.isObject=function(e){return e&&!e.nodeType&&"[object Object]"===Object.prototype.toString.call(e)},qq.isFunction=function(e){return"function"==typeof e},qq.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)||e&&window.ArrayBuffer&&e.buffer&&e.buffer.constructor===ArrayBuffer},qq.isItemList=function(e){return"[object DataTransferItemList]"===Object.prototype.toString.call(e)},qq.isNodeList=function(e){return"[object NodeList]"===Object.prototype.toString.call(e)||e.item&&e.namedItem},qq.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},qq.trimStr=function(e){return String.prototype.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},qq.format=function(e){var t=Array.prototype.slice.call(arguments,1),n=e,i=n.indexOf("{}");return qq.each(t,function(e,t){var o=n.substring(0,i),r=n.substring(i+2);if(n=o+t+r,i=n.indexOf("{}",i+t.length),i<0)return!1}),n},qq.isFile=function(e){return window.File&&"[object File]"===Object.prototype.toString.call(e)},qq.isFileList=function(e){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(e)},qq.isFileOrInput=function(e){return qq.isFile(e)||qq.isInput(e)},qq.isInput=function(e,t){var n=function(e){var n=e.toLowerCase();return t?"file"!==n:"file"===n};return!!(window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(e)&&e.type&&n(e.type))||!!(e.tagName&&"input"===e.tagName.toLowerCase()&&e.type&&n(e.type))},qq.isBlob=function(e){if(window.Blob&&"[object Blob]"===Object.prototype.toString.call(e))return!0},qq.isXhrUploadSupported=function(){var e=document.createElement("input");return e.type="file",void 0!==e.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&"undefined"!=typeof qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(e){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(e){return e.items&&e.items.length>0&&e.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(e,t,n){var i=e.slice||e.mozSlice||e.webkitSlice;return i.call(e,t,n)},qq.arrayBufferToHex=function(e){var t="",n=new Uint8Array(e);return qq.each(n,function(e,n){var i=n.toString(16);i.length<2&&(i="0"+i),t+=i}),t},qq.readBlobToHex=function(e,t,n){var i=qq.sliceBlob(e,t,t+n),o=new FileReader,r=new qq.Promise;return o.onload=function(){r.success(qq.arrayBufferToHex(o.result))},o.onerror=r.failure,o.readAsArrayBuffer(i),r},qq.extend=function(e,t,n){return qq.each(t,function(t,i){n&&qq.isObject(i)?(void 0===e[t]&&(e[t]={}),qq.extend(e[t],i,!0)):e[t]=i}),e},qq.override=function(e,t){var n={},i=t(n);return qq.each(i,function(t,i){void 0!==e[t]&&(n[t]=e[t]),e[t]=i}),e},qq.indexOf=function(e,t,n){if(e.indexOf)return e.indexOf(t,n);n=n||0;var i=e.length;for(n<0&&(n+=i);n=0},qq.safari=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Apple")!==-1},qq.chrome=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Google")!==-1},qq.opera=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Opera")!==-1},qq.firefox=function(){return!qq.edge()&&!qq.ie11()&&navigator.userAgent.indexOf("Mozilla")!==-1&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return navigator.userAgent.toLowerCase().indexOf("android")!==-1},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 6_")!==-1},qq.ios7=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 7_")!==-1},qq.ios8=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_")!==-1},qq.ios800=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_0 ")!==-1},qq.ios=function(){return navigator.userAgent.indexOf("iPad")!==-1||navigator.userAgent.indexOf("iPod")!==-1||navigator.userAgent.indexOf("iPhone")!==-1},qq.iosChrome=function(){return qq.ios()&&navigator.userAgent.indexOf("CriOS")!==-1},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&navigator.userAgent.indexOf("Safari")!==-1},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},qq.toElement=function(){var e=document.createElement("div");return function(t){e.innerHTML=t;var n=e.firstChild;return e.removeChild(n),n}}(),qq.each=function(e,t){var n,i;if(e)if(window.Storage&&e.constructor===window.Storage)for(n=0;n0)return e.substr(t,e.length-t)},qq.getFilename=function(e){return qq.isInput(e)?e.value.replace(/.*(\/|\\)/,""):qq.isFile(e)&&null!==e.fileName&&void 0!==e.fileName?e.fileName:e.name},qq.DisposeSupport=function(){var e=[];return{dispose:function(){var t;do t=e.shift(),t&&t();while(t)},attach:function(){var e=arguments;this.addDisposer(qq(e[0]).attach.apply(this,Array.prototype.slice.call(arguments,1)))},addDisposer:function(t){e.push(t)}}}}(),function(){"use strict";"function"==typeof define&&define.amd?define(function(){return qq}):"undefined"!=typeof module&&module.exports?module.exports=qq:global.qq=qq}(),function(){"use strict";qq.Error=function(e){this.message="[Fine Uploader "+qq.version+"] "+e},qq.Error.prototype=new Error}(),qq.version="5.13.0",qq.supportedFeatures=function(){"use strict";function e(){var e,t=!0;try{e=document.createElement("input"),e.type="file",qq(e).hide(),e.disabled&&(t=!1)}catch(e){t=!1}return t}function t(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/)}function n(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/)}function i(){if(window.XMLHttpRequest){var e=qq.createXhrInstance();return void 0!==e.withCredentials}return!1}function o(){return void 0!==window.XDomainRequest}function r(){return!!i()||o()}function s(){return void 0!==document.createElement("input").webkitdirectory}function a(){try{return!!window.localStorage&&qq.isFunction(window.localStorage.setItem)}catch(e){return!1}}function u(){var e=document.createElement("span");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&!qq.android()&&!qq.ios()}var l,c,d,p,q,h,f,m,g,_,v,b,S,y,C;return l=e(),p=l&&qq.isXhrUploadSupported(),c=p&&!qq.androidStock(),d=p&&u(),q=d&&t(),h=p&&qq.isFileChunkingSupported(),f=p&&h&&a(),m=p&&n(),g=l&&(void 0!==window.postMessage||p),v=i(),_=o(),b=r(),S=s(),y=p&&void 0!==window.FileReader,C=function(){return!!p&&(!qq.androidStock()&&!qq.iosChrome())}(),{ajaxUploading:p,blobUploading:c,canDetermineSize:p,chunking:h,deleteFileCors:b,deleteFileCorsXdr:_,deleteFileCorsXhr:v,dialogElement:!!window.HTMLDialogElement,fileDrop:d,folderDrop:q,folderSelection:S,imagePreviews:y,imageValidation:y,itemSizeValidation:p,pause:h,progressBar:C,resume:f,scaling:y&&c,tiffPreviews:qq.safari(),unlimitedScaledImageSize:!qq.ios(),uploading:l,uploadCors:g,uploadCustomHeaders:p,uploadNonMultipart:p,uploadViaPaste:m}}(),qq.isGenericPromise=function(e){"use strict";return!!(e&&e.then&&qq.isFunction(e.then))},qq.Promise=function(){"use strict";var e,t,n=[],i=[],o=[],r=0;qq.extend(this,{then:function(o,s){return 0===r?(o&&n.push(o),s&&i.push(s)):r===-1?s&&s.apply(null,t):o&&o.apply(null,e),this},done:function(n){return 0===r?o.push(n):n.apply(null,void 0===t?e:t),this},success:function(){return r=1,e=arguments,n.length&&qq.each(n,function(t,n){n.apply(null,e)}),o.length&&qq.each(o,function(t,n){n.apply(null,e)}),this},failure:function(){return r=-1,t=arguments,i.length&&qq.each(i,function(e,n){n.apply(null,t)}),o.length&&qq.each(o,function(e,n){n.apply(null,t)}),this}})},qq.BlobProxy=function(e,t){"use strict";qq.extend(this,{referenceBlob:e,create:function(){return t(e)}})},qq.UploadButton=function(e){"use strict";function t(){var e=document.createElement("input");return e.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME,i),e.setAttribute("title",s.title),o.setMultiple(s.multiple,e),s.folders&&qq.supportedFeatures.folderSelection&&e.setAttribute("webkitdirectory",""),s.acceptFiles&&e.setAttribute("accept",s.acceptFiles),e.setAttribute("type","file"),e.setAttribute("name",s.name),qq(e).css({position:"absolute",right:0,top:0,fontFamily:"Arial",fontSize:qq.ie()&&!qq.ie8()?"3500px":"118px",margin:0,padding:0,cursor:"pointer",opacity:0}),!qq.ie7()&&qq(e).css({height:"100%"}),s.element.appendChild(e),r.attach(e,"change",function(){s.onChange(e)}),r.attach(e,"mouseover",function(){qq(s.element).addClass(s.hoverClass)}),r.attach(e,"mouseout",function(){qq(s.element).removeClass(s.hoverClass)}),r.attach(e,"focus",function(){qq(s.element).addClass(s.focusClass)}),r.attach(e,"blur",function(){qq(s.element).removeClass(s.focusClass)}),e}var n,i,o=this,r=new qq.DisposeSupport,s={acceptFiles:null,element:null,focusClass:"qq-upload-button-focus",folders:!1,hoverClass:"qq-upload-button-hover",ios8BrowserCrashWorkaround:!1,multiple:!1,name:"qqfile",onChange:function(e){},title:null};qq.extend(s,e),i=qq.getUniqueId(),qq(s.element).css({position:"relative",overflow:"hidden",direction:"ltr"}),qq.extend(this,{getInput:function(){return n},getButtonId:function(){return i},setMultiple:function(e,t){var n=t||this.getInput();s.ios8BrowserCrashWorkaround&&qq.ios8()&&(qq.iosChrome()||qq.iosSafariWebView())?n.setAttribute("multiple",""):e?n.setAttribute("multiple",""):n.removeAttribute("multiple")},setAcceptFiles:function(e){e!==s.acceptFiles&&n.setAttribute("accept",e)},reset:function(){n.parentNode&&qq(n).remove(),qq(s.element).removeClass(s.focusClass),n=null,n=t()}}),n=t()},qq.UploadButton.BUTTON_ID_ATTR_NAME="qq-button-id",qq.UploadData=function(e){"use strict";function t(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[n])}),t}return o[e]}function n(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[r[n]])}),t}return o[r[e]]}function i(e){var t=[],n=[].concat(e);return qq.each(n,function(e,n){var i=s[n];void 0!==i&&qq.each(i,function(e,n){t.push(o[n])})}),t}var o=[],r={},s={},a={},u={};qq.extend(this,{addFile:function(t){var n=t.status||qq.status.SUBMITTING,i=o.push({name:t.name,originalName:t.name,uuid:t.uuid,size:null==t.size?-1:t.size,status:n})-1;return t.batchId&&(o[i].batchId=t.batchId,void 0===u[t.batchId]&&(u[t.batchId]=[]),u[t.batchId].push(i)),t.proxyGroupId&&(o[i].proxyGroupId=t.proxyGroupId,void 0===a[t.proxyGroupId]&&(a[t.proxyGroupId]=[]),a[t.proxyGroupId].push(i)),o[i].id=i,r[t.uuid]=i,void 0===s[n]&&(s[n]=[]),s[n].push(i),e.onStatusChange(i,null,n),i},retrieve:function(e){return qq.isObject(e)&&o.length?void 0!==e.id?t(e.id):void 0!==e.uuid?n(e.uuid):e.status?i(e.status):void 0:qq.extend([],o,!0)},reset:function(){o=[],r={},s={},u={}},setStatus:function(t,n){var i=o[t].status,r=qq.indexOf(s[i],t);s[i].splice(r,1),o[t].status=n,void 0===s[n]&&(s[n]=[]),s[n].push(t),e.onStatusChange(t,i,n)},uuidChanged:function(e,t){var n=o[e].uuid;o[e].uuid=t,r[t]=e,delete r[n]},updateName:function(e,t){o[e].name=t},updateSize:function(e,t){o[e].size=t},setParentId:function(e,t){o[e].parentId=t},getIdsInProxyGroup:function(e){var t=o[e].proxyGroupId;return t?a[t]:[]},getIdsInBatch:function(e){var t=o[e].batchId;return u[t]}})},qq.status={SUBMITTING:"submitting",SUBMITTED:"submitted",REJECTED:"rejected",QUEUED:"queued",CANCELED:"canceled",PAUSED:"paused",UPLOADING:"uploading",UPLOAD_RETRYING:"retrying upload",UPLOAD_SUCCESSFUL:"upload successful",UPLOAD_FAILED:"upload failed",DELETE_FAILED:"delete failed",DELETING:"deleting",DELETED:"deleted"},function(){"use strict";qq.basePublicApi={addBlobs:function(e,t,n){this.addFiles(e,t,n)},addInitialFiles:function(e){var t=this;qq.each(e,function(e,n){t._addCannedFile(n)})},addFiles:function(e,t,n){this._maybeHandleIos8SafariWorkaround();var i=0===this._storedIds.length?qq.getUniqueId():this._currentBatchId,o=qq.bind(function(e){this._handleNewFile({blob:e,name:this._options.blobs.defaultName},i,d)},this),r=qq.bind(function(e){this._handleNewFile(e,i,d)},this),s=qq.bind(function(e){var t=qq.canvasToBlob(e);this._handleNewFile({blob:t,name:this._options.blobs.defaultName+".png"},i,d)},this),a=qq.bind(function(e){var t=e.quality&&e.quality/100,n=qq.canvasToBlob(e.canvas,e.type,t);this._handleNewFile({blob:n,name:e.name},i,d)},this),u=qq.bind(function(e){if(qq.isInput(e)&&qq.supportedFeatures.ajaxUploading){var t=Array.prototype.slice.call(e.files),n=this;qq.each(t,function(e,t){n._handleNewFile(t,i,d)})}else this._handleNewFile(e,i,d)},this),l=function(){qq.isFileList(e)&&(e=Array.prototype.slice.call(e)),e=[].concat(e)},c=this,d=[];this._currentBatchId=i,e&&(l(),qq.each(e,function(e,t){qq.isFileOrInput(t)?u(t):qq.isBlob(t)?o(t):qq.isObject(t)?t.blob&&t.name?r(t):t.canvas&&t.name&&a(t):t.tagName&&"canvas"===t.tagName.toLowerCase()?s(t):c.log(t+" is not a valid file container! Ignoring!","warn")}),this.log("Received "+d.length+" files."),this._prepareItemsForUpload(d,t,n))},cancel:function(e){this._handler.cancel(e)},cancelAll:function(){var e=[],t=this;qq.extend(e,this._storedIds),qq.each(e,function(e,n){t.cancel(n)}),this._handler.cancelAll()},clearStoredFiles:function(){this._storedIds=[]},continueUpload:function(e){var t=this._uploadData.retrieve({id:e});return!(!qq.supportedFeatures.pause||!this._options.chunking.enabled)&&(t.status===qq.status.PAUSED?(this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.",e,this.getName(e))),this._uploadFile(e),!0):(this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.",e,this.getName(e)),"error"),!1))},deleteFile:function(e){return this._onSubmitDelete(e)},doesExist:function(e){return this._handler.isValid(e)},drawThumbnail:function(e,t,n,i,o){var r,s,a=new qq.Promise;return this._imageGenerator?(r=this._thumbnailUrls[e],s={customResizeFunction:o,maxSize:n>0?n:null,scale:n>0},!i&&qq.supportedFeatures.imagePreviews&&(r=this.getFile(e)),null==r?a.failure({container:t,error:"File or URL not found."}):this._imageGenerator.generate(r,t,s).then(function(e){a.success(e)},function(e,t){a.failure({container:e,error:t||"Problem generating thumbnail"})})):a.failure({container:t,error:"Missing image generator module"}),a},getButton:function(e){return this._getButton(this._buttonIdsForFileIds[e])},getEndpoint:function(e){return this._endpointStore.get(e)},getFile:function(e){return this._handler.getFile(e)||null},getInProgress:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED]}).length},getName:function(e){return this._uploadData.retrieve({id:e}).name},getParentId:function(e){var t=this.getUploads({id:e}),n=null;return t&&void 0!==t.parentId&&(n=t.parentId),n},getResumableFilesData:function(){return this._handler.getResumableFilesData()},getSize:function(e){return this._uploadData.retrieve({id:e}).size},getNetUploads:function(){return this._netUploaded},getRemainingAllowedItems:function(){var e=this._currentItemLimit;return e>0?e-this._netUploadedOrQueued:null},getUploads:function(e){return this._uploadData.retrieve(e)},getUuid:function(e){return this._uploadData.retrieve({id:e}).uuid},log:function(e,t){!this._options.debug||t&&"info"!==t?t&&"info"!==t&&qq.log("[Fine Uploader "+qq.version+"] "+e,t):qq.log("[Fine Uploader "+qq.version+"] "+e)},pauseUpload:function(e){var t=this._uploadData.retrieve({id:e});if(!qq.supportedFeatures.pause||!this._options.chunking.enabled)return!1;if(qq.indexOf([qq.status.UPLOADING,qq.status.UPLOAD_RETRYING],t.status)>=0){if(this._handler.pause(e))return this._uploadData.setStatus(e,qq.status.PAUSED),!0;this.log(qq.format("Unable to pause file ID {} ({}).",e,this.getName(e)),"error")}else this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.",e,this.getName(e)),"error");return!1},reset:function(){this.log("Resetting uploader..."),this._handler.reset(),this._storedIds=[],this._autoRetries=[],this._retryTimeouts=[],this._preventRetries=[],this._thumbnailUrls=[],qq.each(this._buttons,function(e,t){t.reset()}),this._paramsStore.reset(),this._endpointStore.reset(),this._netUploadedOrQueued=0,this._netUploaded=0,this._uploadData.reset(),this._buttonIdsForFileIds=[],this._pasteHandler&&this._pasteHandler.reset(),this._options.session.refreshOnReset&&this._refreshSessionData(),this._succeededSinceLastAllComplete=[],this._failedSinceLastAllComplete=[],this._totalProgress&&this._totalProgress.reset()},retry:function(e){return this._manualRetry(e)},scaleImage:function(e,t){var n=this;return qq.Scaler.prototype.scaleImage(e,t,{log:qq.bind(n.log,n),getFile:qq.bind(n.getFile,n),uploadData:n._uploadData})},setCustomHeaders:function(e,t){this._customHeadersStore.set(e,t)},setDeleteFileCustomHeaders:function(e,t){this._deleteFileCustomHeadersStore.set(e,t)},setDeleteFileEndpoint:function(e,t){this._deleteFileEndpointStore.set(e,t)},setDeleteFileParams:function(e,t){this._deleteFileParamsStore.set(e,t)},setEndpoint:function(e,t){this._endpointStore.set(e,t)},setForm:function(e){this._updateFormSupportAndParams(e)},setItemLimit:function(e){this._currentItemLimit=e},setName:function(e,t){this._uploadData.updateName(e,t)},setParams:function(e,t){this._paramsStore.set(e,t)},setUuid:function(e,t){return this._uploadData.uuidChanged(e,t)},uploadStoredFiles:function(){0===this._storedIds.length?this._itemError("noFilesError"):this._uploadStoredFiles()}},qq.basePrivateApi={_addCannedFile:function(e){var t=this._uploadData.addFile({uuid:e.uuid,name:e.name,size:e.size,status:qq.status.UPLOAD_SUCCESSFUL});return e.deleteFileEndpoint&&this.setDeleteFileEndpoint(e.deleteFileEndpoint,t),e.deleteFileParams&&this.setDeleteFileParams(e.deleteFileParams,t),e.thumbnailUrl&&(this._thumbnailUrls[t]=e.thumbnailUrl),this._netUploaded++,this._netUploadedOrQueued++,t},_annotateWithButtonId:function(e,t){qq.isFile(e)&&(e.qqButtonId=this._getButtonId(t))},_batchError:function(e){this._options.callbacks.onError(null,null,e,void 0)},_createDeleteHandler:function(){var e=this;return new qq.DeleteFileAjaxRequester({method:this._options.deleteFile.method.toUpperCase(),maxConnections:this._options.maxConnections,uuidParamName:this._options.request.uuidName,customHeaders:this._deleteFileCustomHeadersStore,paramsStore:this._deleteFileParamsStore,endpointStore:this._deleteFileEndpointStore,cors:this._options.cors,log:qq.bind(e.log,e),onDelete:function(t){e._onDelete(t),e._options.callbacks.onDelete(t)},onDeleteComplete:function(t,n,i){e._onDeleteComplete(t,n,i),e._options.callbacks.onDeleteComplete(t,n,i)}})},_createPasteHandler:function(){var e=this;return new qq.PasteSupport({targetElement:this._options.paste.targetElement,callbacks:{log:qq.bind(e.log,e),pasteReceived:function(t){e._handleCheckedCallback({name:"onPasteReceived",callback:qq.bind(e._options.callbacks.onPasteReceived,e,t),onSuccess:qq.bind(e._handlePasteSuccess,e,t),identifier:"pasted image"})}}})},_createStore:function(e,t){var n={},i=e,o={},r=t,s=function(e){return qq.isObject(e)?qq.extend({},e):e},a=function(){return qq.isFunction(r)?r():r},u=function(e,t){r&&qq.isObject(t)&&qq.extend(t,a()),o[e]&&qq.extend(t,o[e])};return{set:function(e,t){null==t?(n={},i=s(e)):n[t]=s(e)},get:function(e){var t;return t=null!=e&&n[e]?n[e]:s(i),u(e,t),s(t)},addReadOnly:function(e,t){qq.isObject(n)&&(null===e?qq.isFunction(t)?r=t:(r=r||{},qq.extend(r,t)):(o[e]=o[e]||{},qq.extend(o[e],t)))},remove:function(e){return delete n[e]},reset:function(){n={},o={},i=e}}},_createUploadDataTracker:function(){var e=this;return new qq.UploadData({getName:function(t){return e.getName(t)},getUuid:function(t){return e.getUuid(t)},getSize:function(t){return e.getSize(t)},onStatusChange:function(t,n,i){e._onUploadStatusChange(t,n,i),e._options.callbacks.onStatusChange(t,n,i),e._maybeAllComplete(t,i),e._totalProgress&&setTimeout(function(){e._totalProgress.onStatusChange(t,n,i)},0)}})},_createUploadButton:function(e){function t(){return!!qq.supportedFeatures.ajaxUploading&&(!(i._options.workarounds.iosEmptyVideos&&qq.ios()&&!qq.ios6()&&i._isAllowedExtension(r,".mov"))&&(void 0===e.multiple?i._options.multiple:e.multiple))}var n,i=this,o=e.accept||this._options.validation.acceptFiles,r=e.allowedExtensions||this._options.validation.allowedExtensions;return n=new qq.UploadButton({acceptFiles:o,element:e.element,focusClass:this._options.classes.buttonFocus,folders:e.folders,hoverClass:this._options.classes.buttonHover,ios8BrowserCrashWorkaround:this._options.workarounds.ios8BrowserCrash,multiple:t(),name:this._options.request.inputName,onChange:function(e){i._onInputChange(e)},title:null==e.title?this._options.text.fileInputTitle:e.title}),this._disposeSupport.addDisposer(function(){n.dispose()}),i._buttons.push(n),n},_createUploadHandler:function(e,t){var n=this,i={},o={debug:this._options.debug,maxConnections:this._options.maxConnections,cors:this._options.cors,paramsStore:this._paramsStore,endpointStore:this._endpointStore,chunking:this._options.chunking,resume:this._options.resume,blobs:this._options.blobs,log:qq.bind(n.log,n),preventRetryParam:this._options.retry.preventRetryResponseProperty,onProgress:function(e,t,o,r){o<0||r<0||(i[e]?i[e].loaded===o&&i[e].total===r||(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)):(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)),i[e]={loaded:o,total:r})},onComplete:function(e,t,o,r){delete i[e];var s,a=n.getUploads({id:e}).status;a!==qq.status.UPLOAD_SUCCESSFUL&&a!==qq.status.UPLOAD_FAILED&&(s=n._onComplete(e,t,o,r),s instanceof qq.Promise?s.done(function(){n._options.callbacks.onComplete(e,t,o,r)}):n._options.callbacks.onComplete(e,t,o,r))},onCancel:function(e,t,i){var o=new qq.Promise;return n._handleCheckedCallback({name:"onCancel",callback:qq.bind(n._options.callbacks.onCancel,n,e,t),onFailure:o.failure,onSuccess:function(){i.then(function(){n._onCancel(e,t)}),o.success()},identifier:e}),o},onUploadPrep:qq.bind(this._onUploadPrep,this),onUpload:function(e,t){n._onUpload(e,t),n._options.callbacks.onUpload(e,t)},onUploadChunk:function(e,t,i){n._onUploadChunk(e,i),n._options.callbacks.onUploadChunk(e,t,i)},onUploadChunkSuccess:function(e,t,i,o){n._options.callbacks.onUploadChunkSuccess.apply(n,arguments)},onResume:function(e,t,i){return n._options.callbacks.onResume(e,t,i)},onAutoRetry:function(e,t,i,o){return n._onAutoRetry.apply(n,arguments)},onUuidChanged:function(e,t){n.log("Server requested UUID change from '"+n.getUuid(e)+"' to '"+t+"'"),n.setUuid(e,t)},getName:qq.bind(n.getName,n),getUuid:qq.bind(n.getUuid,n),getSize:qq.bind(n.getSize,n),setSize:qq.bind(n._setSize,n),getDataByUuid:function(e){return n.getUploads({uuid:e})},isQueued:function(e){var t=n.getUploads({id:e}).status;return t===qq.status.QUEUED||t===qq.status.SUBMITTED||t===qq.status.UPLOAD_RETRYING||t===qq.status.PAUSED},getIdsInProxyGroup:n._uploadData.getIdsInProxyGroup,getIdsInBatch:n._uploadData.getIdsInBatch};return qq.each(this._options.request,function(e,t){o[e]=t}),o.customHeaders=this._customHeadersStore,e&&qq.each(e,function(e,t){o[e]=t}),new qq.UploadHandlerController(o,t)},_fileOrBlobRejected:function(e){this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.REJECTED)},_formatSize:function(e){if(0===e)return e+this._options.text.sizeSymbols[0];var t=-1;do e/=1e3,t++;while(e>999);return Math.max(e,.1).toFixed(1)+this._options.text.sizeSymbols[t]},_generateExtraButtonSpecs:function(){var e=this;this._extraButtonSpecs={},qq.each(this._options.extraButtons,function(t,n){var i=n.multiple,o=qq.extend({},e._options.validation,!0),r=qq.extend({},n);void 0===i&&(i=e._options.multiple),r.validation&&qq.extend(o,n.validation,!0),qq.extend(r,{multiple:i,validation:o},!0),e._initExtraButton(r)})},_getButton:function(e){var t=this._extraButtonSpecs[e];return t?t.element:e===this._defaultButtonId?this._options.button:void 0},_getButtonId:function(e){var t,n,i=e;if(i instanceof qq.BlobProxy&&(i=i.referenceBlob),i&&!qq.isBlob(i)){if(qq.isFile(i))return i.qqButtonId;if("input"===i.tagName.toLowerCase()&&"file"===i.type.toLowerCase())return i.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);if(t=i.getElementsByTagName("input"),qq.each(t,function(e,t){if("file"===t.getAttribute("type"))return n=t,!1}),n)return n.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME)}},_getNotFinished:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED,qq.status.SUBMITTING,qq.status.SUBMITTED,qq.status.PAUSED]}).length},_getValidationBase:function(e){var t=this._extraButtonSpecs[e];return t?t.validation:this._options.validation},_getValidationDescriptor:function(e){return e.file instanceof qq.BlobProxy?{name:qq.getFilename(e.file.referenceBlob),size:e.file.referenceBlob.size}:{name:this.getUploads({id:e.id}).name,size:this.getUploads({id:e.id}).size}},_getValidationDescriptors:function(e){var t=this,n=[];return qq.each(e,function(e,i){n.push(t._getValidationDescriptor(i))}),n},_handleCameraAccess:function(){if(this._options.camera.ios&&qq.ios()){var e="image/*;capture=camera",t=this._options.camera.button,n=t?this._getButtonId(t):this._defaultButtonId,i=this._options;n&&n!==this._defaultButtonId&&(i=this._extraButtonSpecs[n]),i.multiple=!1,null===i.validation.acceptFiles?i.validation.acceptFiles=e:i.validation.acceptFiles+=","+e,qq.each(this._buttons,function(e,t){if(t.getButtonId()===n)return t.setMultiple(i.multiple),t.setAcceptFiles(i.acceptFiles),!1})}},_handleCheckedCallback:function(e){var t=this,n=e.callback();return qq.isGenericPromise(n)?(this.log(e.name+" - waiting for "+e.name+" promise to be fulfilled for "+e.identifier),n.then(function(n){t.log(e.name+" promise success for "+e.identifier),e.onSuccess(n)},function(){e.onFailure?(t.log(e.name+" promise failure for "+e.identifier),e.onFailure()):t.log(e.name+" promise failure for "+e.identifier)})):(n!==!1?e.onSuccess(n):e.onFailure?(this.log(e.name+" - return value was 'false' for "+e.identifier+". Invoking failure callback."),e.onFailure()):this.log(e.name+" - return value was 'false' for "+e.identifier+". Will not proceed."),n)},_handleNewFile:function(e,t,n){var i=this,o=qq.getUniqueId(),r=-1,s=qq.getFilename(e),a=e.blob||e,u=this._customNewFileHandler?this._customNewFileHandler:qq.bind(i._handleNewFileGeneric,i);!qq.isInput(a)&&a.size>=0&&(r=a.size),u(a,s,o,r,n,t,this._options.request.uuidName,{uploadData:i._uploadData,paramsStore:i._paramsStore,addFileToHandler:function(e,t){i._handler.add(e,t),i._netUploadedOrQueued++,i._trackButton(e);
+}})},_handleNewFileGeneric:function(e,t,n,i,o,r){var s=this._uploadData.addFile({uuid:n,name:t,size:i,batchId:r});this._handler.add(s,e),this._trackButton(s),this._netUploadedOrQueued++,o.push({id:s,file:e})},_handlePasteSuccess:function(e,t){var n=e.type.split("/")[1],i=t;null==i&&(i=this._options.paste.defaultName),i+="."+n,this.addFiles({name:i,blob:e})},_initExtraButton:function(e){var t=this._createUploadButton({accept:e.validation.acceptFiles,allowedExtensions:e.validation.allowedExtensions,element:e.element,folders:e.folders,multiple:e.multiple,title:e.fileInputTitle});this._extraButtonSpecs[t.getButtonId()]=e},_initFormSupportAndParams:function(){this._formSupport=qq.FormSupport&&new qq.FormSupport(this._options.form,qq.bind(this.uploadStoredFiles,this),qq.bind(this.log,this)),this._formSupport&&this._formSupport.attachedToForm?(this._paramsStore=this._createStore(this._options.request.params,this._formSupport.getFormInputsAsObject),this._options.autoUpload=this._formSupport.newAutoUpload,this._formSupport.newEndpoint&&(this._options.request.endpoint=this._formSupport.newEndpoint)):this._paramsStore=this._createStore(this._options.request.params)},_isDeletePossible:function(){return!(!qq.DeleteFileAjaxRequester||!this._options.deleteFile.enabled)&&(!this._options.cors.expected||(!!qq.supportedFeatures.deleteFileCorsXhr||!(!qq.supportedFeatures.deleteFileCorsXdr||!this._options.cors.allowXdr)))},_isAllowedExtension:function(e,t){var n=!1;return!e.length||(qq.each(e,function(e,i){if(qq.isString(i)){var o=new RegExp("\\."+i+"$","i");if(null!=t.match(o))return n=!0,!1}}),n)},_itemError:function(e,t,n){function i(e,t){s=s.replace(e,t)}var o,r,s=this._options.messages[e],a=[],u=[].concat(t),l=u[0],c=this._getButtonId(n),d=this._getValidationBase(c);return qq.each(d.allowedExtensions,function(e,t){qq.isString(t)&&a.push(t)}),o=a.join(", ").toLowerCase(),i("{file}",this._options.formatFileName(l)),i("{extensions}",o),i("{sizeLimit}",this._formatSize(d.sizeLimit)),i("{minSizeLimit}",this._formatSize(d.minSizeLimit)),r=s.match(/(\{\w+\})/g),null!==r&&qq.each(r,function(e,t){i(t,u[e])}),this._options.callbacks.onError(null,l,s,void 0),s},_manualRetry:function(e,t){if(this._onBeforeManualRetry(e))return this._netUploadedOrQueued++,this._uploadData.setStatus(e,qq.status.UPLOAD_RETRYING),t?t(e):this._handler.retry(e),!0},_maybeAllComplete:function(e,t){var n=this,i=this._getNotFinished();t===qq.status.UPLOAD_SUCCESSFUL?this._succeededSinceLastAllComplete.push(e):t===qq.status.UPLOAD_FAILED&&this._failedSinceLastAllComplete.push(e),0===i&&(this._succeededSinceLastAllComplete.length||this._failedSinceLastAllComplete.length)&&setTimeout(function(){n._onAllComplete(n._succeededSinceLastAllComplete,n._failedSinceLastAllComplete)},0)},_maybeHandleIos8SafariWorkaround:function(){var e=this;if(this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari())throw setTimeout(function(){window.alert(e._options.messages.unsupportedBrowserIos8Safari)},0),new qq.Error(this._options.messages.unsupportedBrowserIos8Safari)},_maybeParseAndSendUploadError:function(e,t,n,i){if(!n.success)if(i&&200!==i.status&&!n.error)this._options.callbacks.onError(e,t,"XHR returned response code "+i.status,i);else{var o=n.error?n.error:this._options.text.defaultResponseError;this._options.callbacks.onError(e,t,o,i)}},_maybeProcessNextItemAfterOnValidateCallback:function(e,t,n,i,o){var r=this;if(t.length>n)if(e||!this._options.validation.stopOnFirstInvalidFile)setTimeout(function(){var e=r._getValidationDescriptor(t[n]),s=r._getButtonId(t[n].file),a=r._getButton(s);r._handleCheckedCallback({name:"onValidate",callback:qq.bind(r._options.callbacks.onValidate,r,e,a),onSuccess:qq.bind(r._onValidateCallbackSuccess,r,t,n,i,o),onFailure:qq.bind(r._onValidateCallbackFailure,r,t,n,i,o),identifier:"Item '"+e.name+"', size: "+e.size})},0);else if(!e)for(;n0&&this._netUploadedOrQueued+1>n?(this._itemError("retryFailTooManyItems"),!1):(this.log("Retrying upload for '"+t+"' (id: "+e+")..."),!0))):(this.log("'"+e+"' is not a valid file ID","error"),!1)},_onCancel:function(e,t){this._netUploadedOrQueued--,clearTimeout(this._retryTimeouts[e]);var n=qq.indexOf(this._storedIds,e);!this._options.autoUpload&&n>=0&&this._storedIds.splice(n,1),this._uploadData.setStatus(e,qq.status.CANCELED)},_onComplete:function(e,t,n,i){return n.success?(n.thumbnailUrl&&(this._thumbnailUrls[e]=n.thumbnailUrl),this._netUploaded++,this._uploadData.setStatus(e,qq.status.UPLOAD_SUCCESSFUL)):(this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.UPLOAD_FAILED),n[this._options.retry.preventRetryResponseProperty]===!0&&(this._preventRetries[e]=!0)),this._maybeParseAndSendUploadError(e,t,n,i),!!n.success},_onDelete:function(e){this._uploadData.setStatus(e,qq.status.DELETING)},_onDeleteComplete:function(e,t,n){var i=this.getName(e);n?(this._uploadData.setStatus(e,qq.status.DELETE_FAILED),this.log("Delete request for '"+i+"' has failed.","error"),void 0===t.withCredentials?this._options.callbacks.onError(e,i,"Delete request failed",t):this._options.callbacks.onError(e,i,"Delete request failed with response code "+t.status,t)):(this._netUploadedOrQueued--,this._netUploaded--,this._handler.expunge(e),this._uploadData.setStatus(e,qq.status.DELETED),this.log("Delete request for '"+i+"' has succeeded."))},_onInputChange:function(e){var t;if(qq.supportedFeatures.ajaxUploading){for(t=0;t0&&this.addFiles(e);qq.each(this._buttons,function(e,t){t.reset()})},_onProgress:function(e,t,n,i){this._totalProgress&&this._totalProgress.onIndividualProgress(e,n,i)},_onSubmit:function(e,t){},_onSubmitCallbackSuccess:function(e,t){this._onSubmit.apply(this,arguments),this._uploadData.setStatus(e,qq.status.SUBMITTED),this._onSubmitted.apply(this,arguments),this._options.autoUpload?(this._options.callbacks.onSubmitted.apply(this,arguments),this._uploadFile(e)):(this._storeForLater(e),this._options.callbacks.onSubmitted.apply(this,arguments))},_onSubmitDelete:function(e,t,n){var i,o=this.getUuid(e);return t&&(i=qq.bind(t,this,e,o,n)),this._isDeletePossible()?(this._handleCheckedCallback({name:"onSubmitDelete",callback:qq.bind(this._options.callbacks.onSubmitDelete,this,e),onSuccess:i||qq.bind(this._deleteHandler.sendDelete,this,e,o,n),identifier:e}),!0):(this.log("Delete request ignored for ID "+e+", delete feature is disabled or request not possible due to CORS on a user agent that does not support pre-flighting.","warn"),!1)},_onSubmitted:function(e){},_onTotalProgress:function(e,t){this._options.callbacks.onTotalProgress(e,t)},_onUploadPrep:function(e){},_onUpload:function(e,t){this._uploadData.setStatus(e,qq.status.UPLOADING)},_onUploadChunk:function(e,t){},_onUploadStatusChange:function(e,t,n){n===qq.status.PAUSED&&clearTimeout(this._retryTimeouts[e])},_onValidateBatchCallbackFailure:function(e){var t=this;qq.each(e,function(e,n){t._fileOrBlobRejected(n.id)})},_onValidateBatchCallbackSuccess:function(e,t,n,i,o){var r,s=this._currentItemLimit,a=this._netUploadedOrQueued;0===s||a<=s?t.length>0?this._handleCheckedCallback({name:"onValidate",callback:qq.bind(this._options.callbacks.onValidate,this,e[0],o),onSuccess:qq.bind(this._onValidateCallbackSuccess,this,t,0,n,i),onFailure:qq.bind(this._onValidateCallbackFailure,this,t,0,n,i),identifier:"Item '"+t[0].file.name+"', size: "+t[0].file.size}):this._itemError("noFilesError"):(this._onValidateBatchCallbackFailure(t),r=this._options.messages.tooManyItemsError.replace(/\{netItems\}/g,a).replace(/\{itemLimit\}/g,s),this._batchError(r))},_onValidateCallbackFailure:function(e,t,n,i){var o=t+1;this._fileOrBlobRejected(e[t].id,e[t].file.name),this._maybeProcessNextItemAfterOnValidateCallback(!1,e,o,n,i)},_onValidateCallbackSuccess:function(e,t,n,i){var o=this,r=t+1,s=this._getValidationDescriptor(e[t]);this._validateFileOrBlobData(e[t],s).then(function(){o._upload(e[t].id,n,i),o._maybeProcessNextItemAfterOnValidateCallback(!0,e,r,n,i)},function(){o._maybeProcessNextItemAfterOnValidateCallback(!1,e,r,n,i)})},_prepareItemsForUpload:function(e,t,n){if(0===e.length)return void this._itemError("noFilesError");var i=this._getValidationDescriptors(e),o=this._getButtonId(e[0].file),r=this._getButton(o);this._handleCheckedCallback({name:"onValidateBatch",callback:qq.bind(this._options.callbacks.onValidateBatch,this,i,r),onSuccess:qq.bind(this._onValidateBatchCallbackSuccess,this,i,e,t,n,r),onFailure:qq.bind(this._onValidateBatchCallbackFailure,this,e),identifier:"batch validation"})},_preventLeaveInProgress:function(){var e=this;this._disposeSupport.attach(window,"beforeunload",function(t){if(e.getInProgress())return t=t||window.event,t.returnValue=e._options.messages.onLeave,e._options.messages.onLeave})},_refreshSessionData:function(){var e=this,t=this._options.session;qq.Session&&null!=this._options.session.endpoint&&(this._session||(qq.extend(t,{cors:this._options.cors}),t.log=qq.bind(this.log,this),t.addFileRecord=qq.bind(this._addCannedFile,this),this._session=new qq.Session(t)),setTimeout(function(){e._session.refresh().then(function(t,n){e._sessionRequestComplete(),e._options.callbacks.onSessionRequestComplete(t,!0,n)},function(t,n){e._options.callbacks.onSessionRequestComplete(t,!1,n)})},0))},_sessionRequestComplete:function(){},_setSize:function(e,t){this._uploadData.updateSize(e,t),this._totalProgress&&this._totalProgress.onNewSize(e)},_shouldAutoRetry:function(e,t,n){var i=this._uploadData.retrieve({id:e});return!!(!this._preventRetries[e]&&this._options.retry.enableAuto&&i.status!==qq.status.PAUSED&&(void 0===this._autoRetries[e]&&(this._autoRetries[e]=0),this._autoRetries[e]0&&a.sizeLimit&&r>a.sizeLimit?(this._itemError("sizeError",o,i),u.failure()):r>0&&r=0}function n(e){var t=!1;return qq.each(t,function(e,n){if(qq.indexOf(["Accept","Accept-Language","Content-Language","Content-Type"],n)<0)return t=!0,!1}),t}function i(e){return y.cors.expected&&void 0===e.withCredentials}function o(){var e;return(window.XMLHttpRequest||window.ActiveXObject)&&(e=qq.createXhrInstance(),void 0===e.withCredentials&&(e=new XDomainRequest,e.onload=function(){},e.onerror=function(){},e.ontimeout=function(){},e.onprogress=function(){})),e}function r(e,t){var n=S[e].xhr;return n||(n=t?t:y.cors.expected?o():qq.createXhrInstance(),S[e].xhr=n),n}function s(e){var t,n=qq.indexOf(b,e),i=y.maxConnections;delete S[e],b.splice(n,1),b.length>=i&&n=0?o.send(qq.obj2url(a,"")):a&&y.contentType&&y.contentType.toLowerCase().indexOf("application/json")>=0?o.send(JSON.stringify(a)):o.send(a),o}function c(e,t,n){var i=y.endpointStore.get(e),o=S[e].addToPath;return void 0!=o&&(i+="/"+o),v&&t&&(i=qq.obj2url(t,i)),n&&(i=qq.obj2url(n,i)),i}function d(e){return function(){4===r(e).readyState&&a(e)}}function p(e){var t=y.onProgress;t&&(r(e).upload.onprogress=function(n){n.lengthComputable&&t(e,n.loaded,n.total)})}function q(e){return function(){a(e)}}function h(e){return function(){a(e,!0)}}function f(e){var o=r(e),s=y.customHeaders,a=S[e].additionalHeaders||{},u=y.method,l={};i(o)||(y.acceptHeader&&o.setRequestHeader("Accept",y.acceptHeader),y.allowXRequestedWithAndCacheControl&&(y.cors.expected&&t()&&!n(s)||(o.setRequestHeader("X-Requested-With","XMLHttpRequest"),o.setRequestHeader("Cache-Control","no-cache"))),!y.contentType||"POST"!==u&&"PUT"!==u||o.setRequestHeader("Content-Type",y.contentType),qq.extend(l,qq.isFunction(s)?s(e):s),qq.extend(l,a),qq.each(l,function(e,t){o.setRequestHeader(e,t)}))}function m(e){return qq.indexOf(y.successfulResponseCodes[y.method],e)>=0}function g(e,t,n,i,o,r,s){S[e]={addToPath:n,additionalParams:i,additionalQueryParams:o,additionalHeaders:r,payload:s};var a=b.push(e);if(a<=y.maxConnections)return l(e,t)}var _,v,b=[],S={},y={acceptHeader:null,validMethods:["PATCH","POST","PUT"],method:"POST",contentType:"application/x-www-form-urlencoded",maxConnections:3,customHeaders:{},endpointStore:{},paramsStore:{},mandatedParams:{},allowXRequestedWithAndCacheControl:!0,successfulResponseCodes:{DELETE:[200,202,204],PATCH:[200,201,202,203,204],POST:[200,201,202,203,204],PUT:[200,201,202,203,204],GET:[200]},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onSend:function(e){},onComplete:function(e,t,n){},onProgress:null};if(qq.extend(y,e),_=y.log,qq.indexOf(y.validMethods,y.method)<0)throw new Error("'"+y.method+"' is not a supported method for this type of request!");v="GET"===y.method||"DELETE"===y.method,qq.extend(this,{initTransport:function(e){var t,n,i,o,r,s;return{withPath:function(e){return t=e,this},withParams:function(e){return n=e,this},withQueryParams:function(e){return s=e,this},withHeaders:function(e){return i=e,this},withPayload:function(e){return o=e,this},withCacheBuster:function(){return r=!0,this},send:function(a){return r&&qq.indexOf(["GET","DELETE"],y.method)>=0&&(n.qqtimestamp=(new Date).getTime()),g(e,a,t,n,s,i,o)}}},canceled:function(e){s(e)}})},qq.UploadHandler=function(e){"use strict";var t=e.proxy,n={},i=t.onCancel,o=t.getName;qq.extend(this,{add:function(e,t){n[e]=t,n[e].temp={}},cancel:function(e){var t=this,r=new qq.Promise,s=i(e,o(e),r);s.then(function(){t.isValid(e)&&(n[e].canceled=!0,t.expunge(e)),r.success()})},expunge:function(e){delete n[e]},getThirdPartyFileId:function(e){return n[e].key},isValid:function(e){return void 0!==n[e]},reset:function(){n={}},_getFileState:function(e){return n[e]},_setThirdPartyFileId:function(e,t){n[e].key=t},_wasCanceled:function(e){return!!n[e].canceled}})},qq.UploadHandlerController=function(e,t){"use strict";var n,i,o,r=this,s=!1,a=!1,u={paramsStore:{},maxConnections:3,chunking:{enabled:!1,multiple:{enabled:!1}},log:function(e,t){},onProgress:function(e,t,n,i){},onComplete:function(e,t,n,i){},onCancel:function(e,t){},onUploadPrep:function(e){},onUpload:function(e,t){},onUploadChunk:function(e,t,n){},onUploadChunkSuccess:function(e,t,n,i){},onAutoRetry:function(e,t,n,i){},onResume:function(e,t,n){},onUuidChanged:function(e,t){},getName:function(e){},setSize:function(e,t){},isQueued:function(e){},getIdsInProxyGroup:function(e){},getIdsInBatch:function(e){}},l={done:function(e,t,n,i){var r=o._getChunkData(e,t);o._getFileState(e).attemptingResume=!1,delete o._getFileState(e).temp.chunkProgress[t],o._getFileState(e).loaded+=r.size,u.onUploadChunkSuccess(e,o._getChunkDataForCallback(r),n,i)},finalize:function(e){var t=u.getSize(e),n=u.getName(e);i("All chunks have been uploaded for "+e+" - finalizing...."),o.finalizeChunks(e).then(function(r,s){i("Finalize successful for "+e);var a=p.normalizeResponse(r,!0);u.onProgress(e,n,t,t),o._maybeDeletePersistedChunkData(e),p.cleanup(e,a,s)},function(t,o){var r=p.normalizeResponse(t,!1);i("Problem finalizing chunks for file ID "+e+" - "+r.error,"error"),r.reset&&l.reset(e),u.onAutoRetry(e,n,r,o)||p.cleanup(e,r,o)})},handleFailure:function(e,t,n,r){var s=u.getName(t);i("Chunked upload request failed for "+t+", chunk "+e),o.clearCachedChunk(t,e);var d,q=p.normalizeResponse(n,!1);q.reset?l.reset(t):(d=qq.indexOf(o._getFileState(t).chunking.inProgress,e),d>=0&&(o._getFileState(t).chunking.inProgress.splice(d,1),o._getFileState(t).chunking.remaining.unshift(e))),o._getFileState(t).temp.ignoreFailure||(a&&(o._getFileState(t).temp.ignoreFailure=!0,i(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.",JSON.stringify(Object.keys(o._getXhrs(t))),JSON.stringify(o._getFileState(t).chunking.inProgress))),qq.each(o._getXhrs(t),function(e,n){i(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ",t,e,n.readyState)),n.abort(),n._cancelled=!0}),o.moveInProgressToRemaining(t),c.free(t,!0)),u.onAutoRetry(t,s,q,r)||p.cleanup(t,q,r))},hasMoreParts:function(e){return!!o._getFileState(e).chunking.remaining.length},nextPart:function(e){var t=o._getFileState(e).chunking.remaining.shift();return t>=o._getTotalChunks(e)&&(t=null),t},reset:function(e){i("Server or callback has ordered chunking effort to be restarted on next attempt for item ID "+e,"error"),o._maybeDeletePersistedChunkData(e),o.reevaluateChunking(e),o._getFileState(e).loaded=0},sendNext:function(e){var t=u.getSize(e),n=u.getName(e),r=l.nextPart(e),s=o._getChunkData(e,r),d=o._getFileState(e).attemptingResume,q=o._getFileState(e).chunking.inProgress||[];null==o._getFileState(e).loaded&&(o._getFileState(e).loaded=0),d&&u.onResume(e,n,s)===!1&&(l.reset(e),r=l.nextPart(e),s=o._getChunkData(e,r),d=!1),null==r&&0===q.length?l.finalize(e):(i(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.",e,r,s.start+1,s.end,t)),u.onUploadChunk(e,n,o._getChunkDataForCallback(s)),q.push(r),o._getFileState(e).chunking.inProgress=q,a&&c.open(e,r),a&&c.available()&&o._getFileState(e).chunking.remaining.length&&l.sendNext(e),0===s.blob.size?(i(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.",r,e),"error"),l.handleFailure(r,e,"File is no longer available",null)):o.uploadChunk(e,r,d).then(function(t,n){i("Chunked upload request succeeded for "+e+", chunk "+r),o.clearCachedChunk(e,r);var s=o._getFileState(e).chunking.inProgress||[],a=p.normalizeResponse(t,!0),u=qq.indexOf(s,r);i(qq.format("Chunk {} for file {} uploaded successfully.",r,e)),l.done(e,r,a,n),u>=0&&s.splice(u,1),o._maybePersistChunkedState(e),l.hasMoreParts(e)||0!==s.length?l.hasMoreParts(e)?l.sendNext(e):i(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}",e,JSON.stringify(s))):l.finalize(e)},function(t,n){l.handleFailure(r,e,t,n)}).done(function(){o.clearXhr(e,r)}))}},c={_open:[],_openChunks:{},_waiting:[],available:function(){var e=u.maxConnections,t=0,n=0;return qq.each(c._openChunks,function(e,i){t++,n+=i.length}),e-(c._open.length-t+n)},free:function(e,t){var n,r=!t,s=qq.indexOf(c._waiting,e),a=qq.indexOf(c._open,e);delete c._openChunks[e],p.getProxyOrBlob(e)instanceof qq.BlobProxy&&(i("Generated blob upload has ended for "+e+", disposing generated blob."),delete o._getFileState(e).file),s>=0?c._waiting.splice(s,1):r&&a>=0&&(c._open.splice(a,1),n=c._waiting.shift(),n>=0&&(c._open.push(n),p.start(n)))},getWaitingOrConnected:function(){var e=[];return qq.each(c._openChunks,function(t,n){n&&n.length&&e.push(parseInt(t))}),qq.each(c._open,function(t,n){c._openChunks[n]||e.push(parseInt(n))}),e=e.concat(c._waiting)},isUsingConnection:function(e){return qq.indexOf(c._open,e)>=0},open:function(e,t){return null==t&&c._waiting.push(e),!!c.available()&&(null==t?(c._waiting.pop(),c._open.push(e)):!function(){var n=c._openChunks[e]||[];n.push(t),c._openChunks[e]=n}(),!0)},reset:function(){c._waiting=[],c._open=[]}},d={send:function(e,t){o._getFileState(e).loaded=0,i("Sending simple upload request for "+e),o.uploadFile(e).then(function(n,o){i("Simple upload request succeeded for "+e);var r=p.normalizeResponse(n,!0),s=u.getSize(e);u.onProgress(e,t,s,s),p.maybeNewUuid(e,r),p.cleanup(e,r,o)},function(n,o){i("Simple upload request failed for "+e);var r=p.normalizeResponse(n,!1);u.onAutoRetry(e,t,r,o)||p.cleanup(e,r,o)})}},p={cancel:function(e){i("Cancelling "+e),u.paramsStore.remove(e),c.free(e)},cleanup:function(e,t,n){var i=u.getName(e);u.onComplete(e,i,t,n),o._getFileState(e)&&o._clearXhrs&&o._clearXhrs(e),c.free(e)},getProxyOrBlob:function(e){return o.getProxy&&o.getProxy(e)||o.getFile&&o.getFile(e)},initHandler:function(){var e=t?qq[t]:qq.traditional,n=qq.supportedFeatures.ajaxUploading?"Xhr":"Form";o=new e[n+"UploadHandler"](u,{getDataByUuid:u.getDataByUuid,getName:u.getName,getSize:u.getSize,getUuid:u.getUuid,log:i,onCancel:u.onCancel,onProgress:u.onProgress,onUuidChanged:u.onUuidChanged}),o._removeExpiredChunkingRecords&&o._removeExpiredChunkingRecords()},isDeferredEligibleForUpload:function(e){return u.isQueued(e)},maybeDefer:function(e,t){return t&&!o.getFile(e)&&t instanceof qq.BlobProxy?(u.onUploadPrep(e),i("Attempting to generate a blob on-demand for "+e),t.create().then(function(t){i("Generated an on-demand blob for "+e),o.updateBlob(e,t),u.setSize(e,t.size),o.reevaluateChunking(e),p.maybeSendDeferredFiles(e)},function(t){var o={};t&&(o.error=t),i(qq.format("Failed to generate blob for ID {}. Error message: {}.",e,t),"error"),u.onComplete(e,u.getName(e),qq.extend(o,n),null),p.maybeSendDeferredFiles(e),c.free(e)}),!1):p.maybeSendDeferredFiles(e)},maybeSendDeferredFiles:function(e){var t=u.getIdsInProxyGroup(e),n=!1;return t&&t.length?(i("Maybe ready to upload proxy group file "+e),qq.each(t,function(t,i){if(p.isDeferredEligibleForUpload(i)&&o.getFile(i))n=i===e,p.now(i);else if(p.isDeferredEligibleForUpload(i))return!1})):(n=!0,p.now(e)),n},maybeNewUuid:function(e,t){void 0!==t.newUuid&&u.onUuidChanged(e,t.newUuid)},normalizeResponse:function(e,t){var n=e;return qq.isObject(e)||(n={},qq.isString(e)&&!t&&(n.error=e)),n.success=t,n},now:function(e){var t=u.getName(e);if(!r.isValid(e))throw new qq.Error(e+" is not a valid file ID to upload!");u.onUpload(e,t),s&&o._shouldChunkThisFile(e)?l.sendNext(e):d.send(e,t)},start:function(e){var t=p.getProxyOrBlob(e);return t?p.maybeDefer(e,t):(p.now(e),!0)}};qq.extend(this,{add:function(e,t){o.add.apply(this,arguments)},upload:function(e){return!!c.open(e)&&p.start(e)},retry:function(e){return a&&(o._getFileState(e).temp.ignoreFailure=!1),c.isUsingConnection(e)?p.start(e):r.upload(e)},cancel:function(e){var t=o.cancel(e);qq.isGenericPromise(t)?t.then(function(){p.cancel(e)}):t!==!1&&p.cancel(e)},cancelAll:function(){var e,t=c.getWaitingOrConnected();if(t.length)for(e=t.length-1;e>=0;e--)r.cancel(t[e]);c.reset()},getFile:function(e){return o.getProxy&&o.getProxy(e)?o.getProxy(e).referenceBlob:o.getFile&&o.getFile(e);
+},isProxied:function(e){return!(!o.getProxy||!o.getProxy(e))},getInput:function(e){if(o.getInput)return o.getInput(e)},reset:function(){i("Resetting upload handler"),r.cancelAll(),c.reset(),o.reset()},expunge:function(e){if(r.isValid(e))return o.expunge(e)},isValid:function(e){return o.isValid(e)},getResumableFilesData:function(){return o.getResumableFilesData?o.getResumableFilesData():[]},getThirdPartyFileId:function(e){if(r.isValid(e))return o.getThirdPartyFileId(e)},pause:function(e){return!!(r.isResumable(e)&&o.pause&&r.isValid(e)&&o.pause(e))&&(c.free(e),o.moveInProgressToRemaining(e),!0)},isResumable:function(e){return!!o.isResumable&&o.isResumable(e)}}),qq.extend(u,e),i=u.log,s=u.chunking.enabled&&qq.supportedFeatures.chunking,a=s&&u.chunking.concurrent.enabled,n=function(){var e={};return e[u.preventRetryParam]=!0,e}(),p.initHandler()},qq.WindowReceiveMessage=function(e){"use strict";var t={log:function(e,t){}},n={};qq.extend(t,e),qq.extend(this,{receiveMessage:function(e,t){var i=function(e){t(e.data)};window.postMessage?n[e]=qq(window).attach("message",i):log("iframe message passing not supported in this browser!","error")},stopReceivingMessages:function(e){if(window.postMessage){var t=n[e];t&&t()}}})},qq.FormUploadHandler=function(e){"use strict";function t(e){delete c[e],p&&(clearTimeout(d[e]),delete d[e],m.stopReceivingMessages(e));var t=document.getElementById(s._getIframeName(e));t&&(t.setAttribute("src","javascript:false;"),qq(t).remove())}function n(e){return e.split("_")[0]}function i(e){var t=qq.toElement("");return t.setAttribute("id",e),t.style.display="none",document.body.appendChild(t),t}function o(e,t){var i=e.id,o=n(i),r=h(o);l[r]=t,c[o]=qq(e).attach("load",function(){s.getInput(o)&&(f("Received iframe load event for CORS upload request (iframe name "+i+")"),d[i]=setTimeout(function(){var e="No valid message received from loaded iframe for iframe name "+i;f(e,"error"),t({error:e})},1e3))}),m.receiveMessage(i,function(e){f("Received the following window message: '"+e+"'");var t,o=(n(i),s._parseJsonResponse(e)),r=o.uuid;r&&l[r]?(f("Handling response for iframe name "+i),clearTimeout(d[i]),delete d[i],s._detachLoadEvent(i),t=l[r],delete l[r],m.stopReceivingMessages(i),t(o)):r||f("'"+e+"' does not contain a UUID - ignoring.")})}var r=e.options,s=this,a=e.proxy,u=qq.getUniqueId(),l={},c={},d={},p=r.isCors,q=r.inputName,h=a.getUuid,f=a.log,m=new qq.WindowReceiveMessage({log:f});qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,n){e.add(t,{input:n}),n.setAttribute("name",q),n.parentNode&&qq(n).remove()},expunge:function(n){t(n),e.expunge(n)},isValid:function(t){return e.isValid(t)&&void 0!==s._getFileState(t).input}}}),qq.extend(this,{getInput:function(e){return s._getFileState(e).input},_attachLoadEvent:function(e,t){var n;p?o(e,t):c[e.id]=qq(e).attach("load",function(){if(f("Received response for "+e.id),e.parentNode){try{if(e.contentDocument&&e.contentDocument.body&&"false"==e.contentDocument.body.innerHTML)return}catch(e){f("Error when attempting to access iframe during handling of upload response ("+e.message+")","error"),n={success:!1}}t(n)}})},_createIframe:function(e){var t=s._getIframeName(e);return i(t)},_detachLoadEvent:function(e){void 0!==c[e]&&(c[e](),delete c[e])},_getIframeName:function(e){return e+"_"+u},_initFormForUpload:function(e){var t=e.method,n=e.endpoint,i=e.params,o=e.paramsInBody,r=e.targetName,s=qq.toElement(""),a=n;return o?qq.obj2Inputs(i,s):a=qq.obj2url(i,n),s.setAttribute("action",a),s.setAttribute("target",r),s.style.display="none",document.body.appendChild(s),s},_parseJsonResponse:function(e){var t={};try{t=qq.parseJson(e)}catch(e){f("Error when attempting to parse iframe upload response ("+e.message+")","error")}return t}})},qq.XhrUploadHandler=function(e){"use strict";function t(e){qq.each(n._getXhrs(e),function(t,i){var o=n._getAjaxRequester(e,t);i.onreadystatechange=null,i.upload.onprogress=null,i.abort(),o&&o.canceled&&o.canceled(e)})}var n=this,i=e.options.namespace,o=e.proxy,r=e.options.chunking,s=e.options.resume,a=r&&e.options.chunking.enabled&&qq.supportedFeatures.chunking,u=s&&e.options.resume.enabled&&a&&qq.supportedFeatures.resume,l=o.getName,c=o.getSize,d=o.getUuid,p=o.getEndpoint,q=o.getDataByUuid,h=o.onUuidChanged,f=o.onProgress,m=o.log;qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,i){if(qq.isFile(i)||qq.isBlob(i))e.add(t,{file:i});else{if(!(i instanceof qq.BlobProxy))throw new Error("Passed obj is not a File, Blob, or proxy");e.add(t,{proxy:i})}n._initTempState(t),u&&n._maybePrepareForResume(t)},expunge:function(i){t(i),n._maybeDeletePersistedChunkData(i),n._clearXhrs(i),e.expunge(i)}}}),qq.extend(this,{clearCachedChunk:function(e,t){delete n._getFileState(e).temp.cachedChunks[t]},clearXhr:function(e,t){var i=n._getFileState(e).temp;i.xhrs&&delete i.xhrs[t],i.ajaxRequesters&&delete i.ajaxRequesters[t]},finalizeChunks:function(e,t){var i=n._getTotalChunks(e)-1,o=n._getXhr(e,i);return t?(new qq.Promise).success(t(o),o):(new qq.Promise).success({},o)},getFile:function(e){return n.isValid(e)&&n._getFileState(e).file},getProxy:function(e){return n.isValid(e)&&n._getFileState(e).proxy},getResumableFilesData:function(){var e=[];return n._iterateResumeRecords(function(t,i){n.moveInProgressToRemaining(null,i.chunking.inProgress,i.chunking.remaining);var o={name:i.name,remaining:i.chunking.remaining,size:i.size,uuid:i.uuid};i.key&&(o.key=i.key),e.push(o)}),e},isResumable:function(e){return!!r&&n.isValid(e)&&!n._getFileState(e).notResumable},moveInProgressToRemaining:function(e,t,i){var o=t||n._getFileState(e).chunking.inProgress,r=i||n._getFileState(e).chunking.remaining;o&&(m(qq.format("Moving these chunks from in-progress {}, to remaining.",JSON.stringify(o))),o.reverse(),qq.each(o,function(e,t){r.unshift(t)}),o.length=0)},pause:function(e){if(n.isValid(e))return m(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.",e,l(e))),n._getFileState(e).paused=!0,t(e),!0},reevaluateChunking:function(e){if(r&&n.isValid(e)){var t,i,o=n._getFileState(e);if(delete o.chunking,o.chunking={},t=n._getTotalChunks(e),t>1||r.mandatory){for(o.chunking.enabled=!0,o.chunking.parts=t,o.chunking.remaining=[],i=0;i=o?o:a+i,l=n._getTotalChunks(e),d=this._getFileState(e).temp.cachedChunks,p=d[t]||qq.sliceBlob(s,a,u);return d[t]=p,{part:t,start:a,end:u,count:l,blob:p,size:u-a}},_getChunkDataForCallback:function(e){return{partIndex:e.part,startByte:e.start+1,endByte:e.end,totalParts:e.count}},_getLocalStorageId:function(e){var t="5.0",n=l(e),o=c(e),s=r.partSize,a=p(e);return qq.format("qq{}resume{}-{}-{}-{}-{}",i,t,n,o,s,a)},_getMimeType:function(e){return n.getFile(e).type},_getPersistableData:function(e){return n._getFileState(e).chunking},_getTotalChunks:function(e){if(r){var t=c(e),n=r.partSize;return Math.ceil(t/n)}},_getXhr:function(e,t){var i=null==t?-1:t;return n._getFileState(e).temp.xhrs[i]},_getXhrs:function(e){return n._getFileState(e).temp.xhrs},_iterateResumeRecords:function(e){u&&qq.each(localStorage,function(t,n){if(0===t.indexOf(qq.format("qq{}resume",i))){var o=JSON.parse(n);e(t,o)}})},_initTempState:function(e){n._getFileState(e).temp={ajaxRequesters:{},chunkProgress:{},xhrs:{},cachedChunks:{}}},_markNotResumable:function(e){n._getFileState(e).notResumable=!0},_maybeDeletePersistedChunkData:function(e){var t;return!!(u&&n.isResumable(e)&&(t=n._getLocalStorageId(e),t&&localStorage.getItem(t)))&&(localStorage.removeItem(t),!0)},_maybePrepareForResume:function(e){var t,i,o=n._getFileState(e);u&&void 0===o.key&&(t=n._getLocalStorageId(e),i=localStorage.getItem(t),i&&(i=JSON.parse(i),q(i.uuid)?n._markNotResumable(e):(m(qq.format("Identified file with ID {} and name of {} as resumable.",e,l(e))),h(e,i.uuid),o.key=i.key,o.chunking=i.chunking,o.loaded=i.loaded,o.attemptingResume=!0,n.moveInProgressToRemaining(e))))},_maybePersistChunkedState:function(e){var t,i,o=n._getFileState(e);if(u&&n.isResumable(e)){t=n._getLocalStorageId(e),i={name:l(e),size:c(e),uuid:d(e),key:o.key,chunking:o.chunking,loaded:o.loaded,lastUpdated:Date.now()};try{localStorage.setItem(t,JSON.stringify(i))}catch(t){m(qq.format("Unable to save resume data for '{}' due to error: '{}'.",e,t.toString()),"warn")}}},_registerProgressHandler:function(e,t,i){var o=n._getXhr(e,t),r=l(e),s={simple:function(t,n){var i=c(e);t===n?f(e,r,i,i):f(e,r,t>=i?i-1:t,i)},chunked:function(o,s){var a=n._getFileState(e).temp.chunkProgress,u=n._getFileState(e).loaded,l=o,d=s,p=c(e),q=l-(d-i),h=u;a[t]=q,qq.each(a,function(e,t){h+=t}),f(e,r,h,p)}};o.upload.onprogress=function(e){if(e.lengthComputable){var t=null==i?"simple":"chunked";s[t](e.loaded,e.total)}}},_registerXhr:function(e,t,i,o){var r=null==t?-1:t,s=n._getFileState(e).temp;return s.xhrs=s.xhrs||{},s.ajaxRequesters=s.ajaxRequesters||{},s.xhrs[r]=i,o&&(s.ajaxRequesters[r]=o),i},_removeExpiredChunkingRecords:function(){var e=s.recordsExpireIn;n._iterateResumeRecords(function(t,n){var i=new Date(n.lastUpdated);i.setDate(i.getDate()+e),i.getTime()<=Date.now()&&(m("Removing expired resume record with key "+t),localStorage.removeItem(t))})},_shouldChunkThisFile:function(e){var t=n._getFileState(e);return t.chunking||n.reevaluateChunking(e),t.chunking.enabled}})},qq.DeleteFileAjaxRequester=function(e){"use strict";function t(){return"POST"===i.method.toUpperCase()?{_method:"DELETE"}:{}}var n,i={method:"DELETE",uuidParamName:"qquuid",endpointStore:{},maxConnections:3,customHeaders:function(e){return{}},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onDelete:function(e){},onDeleteComplete:function(e,t,n){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["POST","DELETE"],method:i.method,endpointStore:i.endpointStore,paramsStore:i.paramsStore,mandatedParams:t(),maxConnections:i.maxConnections,customHeaders:function(e){return i.customHeaders.get(e)},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete,cors:i.cors})),qq.extend(this,{sendDelete:function(e,t,o){var r=o||{};i.log("Submitting delete file request for "+e),"DELETE"===i.method?n.initTransport(e).withPath(t).withParams(r).send():(r[i.uuidParamName]=t,n.initTransport(e).withParams(r).send())}})},function(){function e(e){var t,n=e.naturalWidth,i=e.naturalHeight,o=document.createElement("canvas");return n*i>1048576&&(o.width=o.height=1,t=o.getContext("2d"),t.drawImage(e,-n+1,0),0===t.getImageData(0,0,1,1).data[3])}function t(e,t,n){var i,o,r,s,a=document.createElement("canvas"),u=0,l=n,c=n;for(a.width=1,a.height=n,i=a.getContext("2d"),i.drawImage(e,0,0),o=i.getImageData(0,0,1,n).data;c>u;)r=o[4*(c-1)+3],0===r?l=c:u=c,c=l+u>>1;return s=c/n,0===s?1:s}function n(e,t,n,i){var r=document.createElement("canvas"),s=n.mime||"image/jpeg",a=new qq.Promise;return o(e,t,r,n,i).then(function(){a.success(r.toDataURL(s,n.quality||.8))}),a}function i(e){var t=5241e3;if(!qq.ios())throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");if(e.origHeight*e.origWidth>t)return{newHeight:Math.round(Math.sqrt(t*(e.origHeight/e.origWidth))),newWidth:Math.round(Math.sqrt(t*(e.origWidth/e.origHeight)))}}function o(n,o,a,u,l){var c,d=n.naturalWidth,p=n.naturalHeight,q=u.width,h=u.height,f=a.getContext("2d"),m=new qq.Promise;return f.save(),u.resize?r({blob:o,canvas:a,image:n,imageHeight:p,imageWidth:d,orientation:u.orientation,resize:u.resize,targetHeight:h,targetWidth:q}):(qq.supportedFeatures.unlimitedScaledImageSize||(c=i({origWidth:q,origHeight:h}),c&&(qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h",q,h,c.newWidth,c.newHeight),"warn"),q=c.newWidth,h=c.newHeight)),s(a,q,h,u.orientation),qq.ios()?!function(){e(n)&&(d/=2,p/=2);var i,o,r,s=1024,a=document.createElement("canvas"),u=l?t(n,d,p):1,c=Math.ceil(s*q/d),m=Math.ceil(s*h/p/u),g=0,_=0;for(a.width=a.height=s,i=a.getContext("2d");gc&&(u=c,l=a*u/s<<0),d&&l>d&&(l=d,u=s*l/a<<0),i={width:u,height:l},qq.each(t,function(e,t){i[e]=t}),"img"===q?!function(){var t=e.src;n(r.srcImage,r.blob,i,p).then(function(n){e.src=n,t===e.src&&e.onload()})}():"canvas"===q&&o(this.srcImage,this.blob,e,i,p),void("function"==typeof this.onrender&&this.onrender(e)))},qq.MegaPixImage=a}(),qq.ImageGenerator=function(e){"use strict";function t(e){return"img"===e.tagName.toLowerCase()}function n(e){return"canvas"===e.tagName.toLowerCase()}function i(){return void 0!==(new Image).crossOrigin}function o(){var e=document.createElement("canvas");return e.getContext&&e.getContext("2d")}function r(e){var t=e.split("/"),n=t[t.length-1].split("?")[0],i=qq.getExtension(n);switch(i=i&&i.toLowerCase()){case"jpeg":case"jpg":return"image/jpeg";case"png":return"image/png";case"bmp":return"image/bmp";case"gif":return"image/gif";case"tiff":case"tif":return"image/tiff"}}function s(e){var t,n,i,o=document.createElement("a");return o.href=e,t=o.protocol,i=o.port,n=o.hostname,t.toLowerCase()!==window.location.protocol.toLowerCase()||(n.toLowerCase()!==window.location.hostname.toLowerCase()||i!==window.location.port&&!qq.ie())}function a(t,n){t.onload=function(){t.onload=null,t.onerror=null,n.success(t)},t.onerror=function(){t.onload=null,t.onerror=null,e("Problem drawing thumbnail!","error"),n.failure(t,"Problem drawing thumbnail!")}}function u(e,t){e.qqImageRendered=function(){t.success(e)}}function l(i,o){var r=t(i)||n(i);return t(i)?a(i,o):n(i)?u(i,o):(o.failure(i),e(qq.format("Element container of type {} is not supported!",i.tagName),"error")),r}function c(t,n,i){var o=new qq.Promise,r=new qq.Identify(t,e),s=i.maxSize,a=null==i.orient||i.orient,u=function(){n.onerror=null,n.onload=null,e("Could not render preview, file may be too large!","error"),o.failure(n,"Browser cannot render image!")};return r.isPreviewable().then(function(r){var c={parse:function(){return(new qq.Promise).success()}},d=a?new qq.Exif(t,e):c,p=new qq.MegaPixImage(t,u);l(n,o)&&d.parse().then(function(e){var t=e&&e.Orientation;p.render(n,{maxWidth:s,maxHeight:s,orientation:t,mime:r,resize:i.customResizeFunction})},function(t){e(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.",t)),p.render(n,{maxWidth:s,maxHeight:s,mime:r,resize:i.customResizeFunction})})},function(){e("Not previewable"),o.failure(n,"Not previewable")}),o}function d(e,t,n,i,o){var a=new Image,u=new qq.Promise;l(a,u),s(e)&&(a.crossOrigin="anonymous"),a.src=e,u.then(function(){l(t,n);var s=new qq.MegaPixImage(a);s.render(t,{maxWidth:i,maxHeight:i,mime:r(e),resize:o})},n.failure)}function p(e,t,n,i){l(t,n),qq(t).css({maxWidth:i+"px",maxHeight:i+"px"}),t.src=e}function q(e,r,a){var u=new qq.Promise,c=a.scale,q=c?a.maxSize:null;return c&&t(r)?o()?s(e)&&!i()?p(e,r,u,q):d(e,r,u,q):p(e,r,u,q):n(r)?d(e,r,u,q):l(r,u)&&(r.src=e),u}qq.extend(this,{generate:function(t,n,i){return qq.isString(t)?(e("Attempting to update thumbnail based on server response."),q(t,n,i||{})):(e("Attempting to draw client-side image preview."),c(t,n,i||{}))}}),this._testing={},this._testing.isImg=t,this._testing.isCanvas=n,this._testing.isCrossOrigin=s,this._testing.determineMimeOfFileName=r},qq.Exif=function(e,t){"use strict";function n(e){for(var t=0,n=0;e.length>0;)t+=parseInt(e.substring(0,2),16)*Math.pow(2,n),e=e.substring(2,e.length),n+=8;return t}function i(t,n){var o=t,r=n;return void 0===o&&(o=2,r=new qq.Promise),qq.readBlobToHex(e,o,4).then(function(e){var t,n=/^ffe([0-9])/.exec(e);n?"1"!==n[1]?(t=parseInt(e.slice(4,8),16),i(o+t+2,r)):r.success(o):r.failure("No EXIF header to be found!")}),r}function o(){var t=new qq.Promise;return qq.readBlobToHex(e,0,6).then(function(e){0!==e.indexOf("ffd8")?t.failure("Not a valid JPEG!"):i().then(function(e){t.success(e)},function(e){t.failure(e)})}),t}function r(t){var n=new qq.Promise;return qq.readBlobToHex(e,t+10,2).then(function(e){n.success("4949"===e)}),n}function s(t,i){var o=new qq.Promise;return qq.readBlobToHex(e,t+18,2).then(function(e){return i?o.success(n(e)):void o.success(parseInt(e,16))}),o}function a(t,n){var i=t+20,o=12*n;return qq.readBlobToHex(e,i,o)}function u(e){for(var t=[],n=0;n+24<=e.length;)t.push(e.slice(n,n+24)),n+=24;return t}function l(e,t){var i=16,o=qq.extend([],c),r={};return qq.each(t,function(t,s){var a,u,l,c=s.slice(0,4),p=e?n(c):parseInt(c,16),q=o.indexOf(p);if(q>=0&&(u=d[p].name,l=d[p].bytes,a=s.slice(i,i+2*l),r[u]=e?n(a):parseInt(a,16),o.splice(q,1)),0===o.length)return!1}),r}var c=[274],d={274:{name:"Orientation",bytes:2}};qq.extend(this,{parse:function(){var n=new qq.Promise,i=function(e){t(qq.format("EXIF header parse failed: '{}' ",e)),n.failure(e)};return o().then(function(o){t(qq.format("Moving forward with EXIF header parsing for '{}'",void 0===e.name?"blob":e.name)),r(o).then(function(e){t(qq.format("EXIF Byte order is {} endian",e?"little":"big")),s(o,e).then(function(r){t(qq.format("Found {} APP1 directory entries",r)),a(o,r).then(function(i){var o=u(i),r=l(e,o);t("Successfully parsed some EXIF tags"),n.success(r)},i)},i)},i)},i),n}}),this._testing={},this._testing.parseLittleEndian=n},qq.Identify=function(e,t){"use strict";function n(e,t){var n=!1,i=[].concat(e);return qq.each(i,function(e,i){if(0===t.indexOf(i))return n=!0,!1}),n}qq.extend(this,{isPreviewable:function(){var i=this,o=new qq.Promise,r=!1,s=void 0===e.name?"blob":e.name;return t(qq.format("Attempting to determine if {} can be rendered in this browser",s)),t("First pass: check type attribute of blob object."),this.isPreviewableSync()?(t("Second pass: check for magic bytes in file header."),qq.readBlobToHex(e,0,4).then(function(e){qq.each(i.PREVIEWABLE_MIME_TYPES,function(t,i){if(n(i,e))return("image/tiff"!==t||qq.supportedFeatures.tiffPreviews)&&(r=!0,o.success(t)),!1}),t(qq.format("'{}' is {} able to be rendered in this browser",s,r?"":"NOT")),r||o.failure()},function(){t("Error reading file w/ name '"+s+"'. Not able to be rendered in this browser."),o.failure()})):o.failure(),o},isPreviewableSync:function(){var n=e.type,i=qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES),n)>=0,o=!1,r=void 0===e.name?"blob":e.name;return i&&(o="image/tiff"!==n||qq.supportedFeatures.tiffPreviews),!o&&t(r+" is not previewable in this browser per the blob's type attr"),o}})},qq.Identify.prototype.PREVIEWABLE_MIME_TYPES={"image/jpeg":"ffd8ff","image/gif":"474946","image/png":"89504e","image/bmp":"424d","image/tiff":["49492a00","4d4d002a"]},qq.ImageValidation=function(e,t){"use strict";function n(e){var t=!1;return qq.each(e,function(e,n){if(n>0)return t=!0,!1}),t}function i(){var n=new qq.Promise;return new qq.Identify(e,t).isPreviewable().then(function(){var i=new Image,o=window.URL&&window.URL.createObjectURL?window.URL:window.webkitURL&&window.webkitURL.createObjectURL?window.webkitURL:null;o?(i.onerror=function(){t("Cannot determine dimensions for image. May be too large.","error"),n.failure()},i.onload=function(){n.success({width:this.width,height:this.height})},i.src=o.createObjectURL(e)):(t("No createObjectURL function available to generate image URL!","error"),n.failure())},n.failure),n}function o(e,t){var n;return qq.each(e,function(e,i){if(i>0){var o=/(max|min)(Width|Height)/.exec(e),r=o[2].charAt(0).toLowerCase()+o[2].slice(1),s=t[r];switch(o[1]){case"min":if(si)return n=e,!1}}}),n}this.validate=function(e){var r=new qq.Promise;return t("Attempting to validate image."),n(e)?i().then(function(t){var n=o(e,t);n?r.failure(n):r.success()},r.success):r.success(),r}},qq.Session=function(e){"use strict";function t(e){return!!qq.isArray(e)||void i.log("Session response is not an array.","error")}function n(e,n,o,r){var s=!1;n=n&&t(e),n&&qq.each(e,function(e,t){if(null==t.uuid)s=!0,i.log(qq.format("Session response item {} did not include a valid UUID - ignoring.",e),"error");else if(null==t.name)s=!0,i.log(qq.format("Session response item {} did not include a valid name - ignoring.",e),"error");else try{return i.addFileRecord(t),!0}catch(e){s=!0,i.log(e.message,"error")}return!1}),r[n&&!s?"success":"failure"](e,o)}var i={endpoint:null,params:{},customHeaders:{},cors:{},addFileRecord:function(e){},log:function(e,t){}};qq.extend(i,e,!0),this.refresh=function(){var e=new qq.Promise,t=function(t,i,o){n(t,i,o,e)},o=qq.extend({},i),r=new qq.SessionAjaxRequester(qq.extend(o,{onComplete:t}));return r.queryServer(),e}},qq.SessionAjaxRequester=function(e){"use strict";function t(e,t,n){var o=null;if(null!=t.responseText)try{o=qq.parseJson(t.responseText)}catch(e){i.log("Problem parsing session response: "+e.message,"error"),n=!0}i.onComplete(o,!n,t)}var n,i={endpoint:null,customHeaders:{},params:{},cors:{expected:!1,sendCredentials:!1},onComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",endpointStore:{get:function(){return i.endpoint}},customHeaders:i.customHeaders,log:i.log,onComplete:t,cors:i.cors})),qq.extend(this,{queryServer:function(){var e=qq.extend({},i.params);i.log("Session query request."),n.initTransport("sessionRefresh").withParams(e).withCacheBuster().send()}})},qq.Scaler=function(e,t){"use strict";var n=e.customResizer,i=e.sendOriginal,o=e.orient,r=e.defaultType,s=e.defaultQuality/100,a=e.failureText,u=e.includeExif,l=this._getSortedSizes(e.sizes);qq.extend(this,{enabled:qq.supportedFeatures.scaling&&l.length>0,getFileRecords:function(e,c,d){var p=this,q=[],h=d.blob?d.blob:d,f=new qq.Identify(h,t);return f.isPreviewableSync()?(qq.each(l,function(e,i){var l=p._determineOutputType({defaultType:r,requestedType:i.type,refType:h.type});q.push({uuid:qq.getUniqueId(),name:p._getName(c,{name:i.name,type:l,refType:h.type}),blob:new qq.BlobProxy(h,qq.bind(p._generateScaledImage,p,{customResizeFunction:n,maxSize:i.maxSize,orient:o,type:l,quality:s,failedText:a,includeExif:u,log:t}))})}),q.push({uuid:e,name:c,size:h.size,blob:i?h:null})):q.push({uuid:e,name:c,size:h.size,blob:h}),q},handleNewFile:function(e,t,n,i,o,r,s,a){var u=this,l=(e.qqButtonId||e.blob&&e.blob.qqButtonId,[]),c=null,d=a.addFileToHandler,p=a.uploadData,q=a.paramsStore,h=qq.getUniqueId();qq.each(u.getFileRecords(n,t,e),function(e,t){var n,i=t.size;t.blob instanceof qq.BlobProxy&&(i=-1),n=p.addFile({uuid:t.uuid,name:t.name,size:i,batchId:r,proxyGroupId:h}),t.blob instanceof qq.BlobProxy?l.push(n):c=n,t.blob?(d(n,t.blob),o.push({id:n,file:t.blob})):p.setStatus(n,qq.status.REJECTED)}),null!==c&&(qq.each(l,function(e,t){var n={qqparentuuid:p.retrieve({id:c}).uuid,qqparentsize:p.retrieve({id:c}).size};n[s]=p.retrieve({id:t}).uuid,p.setParentId(t,c),q.addReadOnly(t,n)}),l.length&&!function(){var e={};e[s]=p.retrieve({id:c}).uuid,q.addReadOnly(c,e)}())}})},qq.extend(qq.Scaler.prototype,{scaleImage:function(e,t,n){"use strict";if(!qq.supportedFeatures.scaling)throw new qq.Error("Scaling is not supported in this browser!");var i=new qq.Promise,o=n.log,r=n.getFile(e),s=n.uploadData.retrieve({id:e}),a=s&&s.name,u=s&&s.uuid,l={customResizer:t.customResizer,sendOriginal:!1,orient:t.orient,defaultType:t.type||null,defaultQuality:t.quality,failedToScaleText:"Unable to scale",sizes:[{name:"",maxSize:t.maxSize}]},c=new qq.Scaler(l,o);return qq.Scaler&&qq.supportedFeatures.imagePreviews&&r?qq.bind(function(){var t=c.getFileRecords(u,a,r)[0];t&&t.blob instanceof qq.BlobProxy?t.blob.create().then(i.success,i.failure):(o(e+" is not a scalable image!","error"),i.failure())},this)():(i.failure(),o("Could not generate requested scaled image for "+e+". Scaling is either not possible in this browser, or the file could not be located.","error")),i},_determineOutputType:function(e){"use strict";var t=e.requestedType,n=e.defaultType,i=e.refType;return n||t?t&&qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES),t)>=0?"image/tiff"===t?qq.supportedFeatures.tiffPreviews?t:n:t:n:"image/jpeg"!==i?"image/png":i},_getName:function(e,t){"use strict";var n=e.lastIndexOf("."),i=t.type||"image/png",o=t.refType,r="",s=qq.getExtension(e),a="";return t.name&&t.name.trim().length&&(a=" ("+t.name+")"),n>=0?(r=e.substr(0,n),o!==i&&(s=i.split("/")[1]),r+=a+"."+s):r=e+a,r},_getSortedSizes:function(e){"use strict";return e=qq.extend([],e),e.sort(function(e,t){return e.maxSize>t.maxSize?1:e.maxSize=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),n=e.split(",")[0].split(":")[1].split(";")[0],i=new ArrayBuffer(t.length),o=new Uint8Array(i),qq.each(t,function(e,t){o[e]=t.charCodeAt(0)}),this._createBlob(i,n)},_createBlob:function(e,t){"use strict";var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})}}),qq.ExifRestorer=function(){var e={};return e.KEY_STR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e.encode64=function(e){var t,n,i,o,r,s="",a="",u="",l=0;do t=e[l++],n=e[l++],a=e[l++],i=t>>2,o=(3&t)<<4|n>>4,r=(15&n)<<2|a>>6,u=63&a,isNaN(n)?r=u=64:isNaN(a)&&(u=64),s=s+this.KEY_STR.charAt(i)+this.KEY_STR.charAt(o)+this.KEY_STR.charAt(r)+this.KEY_STR.charAt(u),t=n=a="",i=o=r=u="";while(le.length)break}return n},e.decode64=function(e){var t,n,i,o,r,s="",a="",u=0,l=[],c=/[^A-Za-z0-9\+\/\=]/g;if(c.exec(e))throw new Error("There were invalid base64 characters in the input text. Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");do i=this.KEY_STR.indexOf(e.charAt(u++)),o=this.KEY_STR.indexOf(e.charAt(u++)),r=this.KEY_STR.indexOf(e.charAt(u++)),a=this.KEY_STR.indexOf(e.charAt(u++)),t=i<<2|o>>4,n=(15&o)<<4|r>>2,s=(3&r)<<6|a,l.push(t),64!=r&&l.push(n),64!=a&&l.push(s),t=n=s="",i=o=r=a="";while(u=0)return n=!1,!1}),n},l=function(e){p(e,-1,-1),delete n[e]},c=function(e,t,n){(0===t.length||u(t,n))&&(a(o,o),this.reset())},d=function(e){var i=t(e);i>0&&(p(e,0,i),n[e]={loaded:0,total:i})},p=function(e,t,r){var s=n[e]?n[e].loaded:0,u=n[e]?n[e].total:0;t===-1&&r===-1?(i-=s,o-=u):(t&&(i+=t-s),r&&(o+=r-u)),a(i,o)};qq.extend(this,{onAllComplete:c,onStatusChange:function(e,t,n){n===qq.status.CANCELED||n===qq.status.REJECTED?l(e):n===qq.status.SUBMITTING&&d(e)},onIndividualProgress:function(e,t,i){p(e,t,i),n[e]={loaded:t,total:i}},onNewSize:function(e){d(e)},reset:function(){n={},i=0,o=0}})},qq.PasteSupport=function(e){"use strict";function t(e){return e.type&&0===e.type.indexOf("image/")}function n(){r=qq(o.targetElement).attach("paste",function(e){var n=e.clipboardData;n&&qq.each(n.items,function(e,n){if(t(n)){var i=n.getAsFile();o.callbacks.pasteReceived(i)}})})}function i(){r&&r()}var o,r;o={targetElement:null,callbacks:{log:function(e,t){},pasteReceived:function(e){}}},qq.extend(o,e),n(),qq.extend(this,{reset:function(){i()}})},qq.FormSupport=function(e,t,n){"use strict";function i(e){e.getAttribute("action")&&(a.newEndpoint=e.getAttribute("action"))}function o(e,t){return!(e.checkValidity&&!e.checkValidity())||(n("Form did not pass validation checks - will not upload.","error"),void t())}function r(e){var n=e.submit;
+qq(e).attach("submit",function(i){i=i||window.event,i.preventDefault?i.preventDefault():i.returnValue=!1,o(e,n)&&t()}),e.submit=function(){o(e,n)&&t()}}function s(e){return e&&(qq.isString(e)&&(e=document.getElementById(e)),e&&(n("Attaching to form element."),i(e),u&&r(e))),e}var a=this,u=e.interceptSubmit,l=e.element,c=e.autoUpload;qq.extend(this,{newEndpoint:null,newAutoUpload:c,attachedToForm:!1,getFormInputsAsObject:function(){return null==l?null:a._form2Obj(l)}}),l=s(l),this.attachedToForm=!!l},qq.extend(qq.FormSupport.prototype,{_form2Obj:function(e){"use strict";var t={},n=function(e){var t=["button","image","reset","submit"];return qq.indexOf(t,e.toLowerCase())<0},i=function(e){return qq.indexOf(["checkbox","radio"],e.toLowerCase())>=0},o=function(e){return!(!i(e.type)||e.checked)||e.disabled&&"hidden"!==e.type.toLowerCase()},r=function(e){var t=null;return qq.each(qq(e).children(),function(e,n){if("option"===n.tagName.toLowerCase()&&n.selected)return t=n.value,!1}),t};return qq.each(e.elements,function(e,i){if(!qq.isInput(i,!0)&&"textarea"!==i.tagName.toLowerCase()||!n(i.type)||o(i)){if("select"===i.tagName.toLowerCase()&&!o(i)){var s=r(i);null!==s&&(t[i.name]=s)}}else t[i.name]=i.value}),t}}),qq.traditional=qq.traditional||{},qq.traditional.FormUploadHandler=function(e,t){"use strict";function n(e,t){var n,i,r;try{i=t.contentDocument||t.contentWindow.document,r=i.body.innerHTML,a("converting iframe's innerHTML to JSON"),a("innerHTML = "+r),r&&r.match(/^1&&!l.allowMultipleItems?(l.callbacks.processingDroppedFilesComplete([]),l.callbacks.dropError("tooManyFilesError",""),t.dropDisabled(!1),o.failure()):(q=[],qq.isFolderDropSupported(e)?qq.each(e.items,function(e,t){var r=t.webkitGetAsEntry();r&&(r.isFile?q.push(t.getAsFile()):i.push(n(r).done(function(){i.pop(),0===i.length&&o.success()})))}):q=e.files,0===i.length&&o.success()),o}function r(e){var n=new qq.UploadDropZone({HIDE_ZONES_EVENT_NAME:c,element:e,onEnter:function(t){qq(e).addClass(l.classes.dropActive),t.stopPropagation()},onLeaveNotDescendants:function(t){qq(e).removeClass(l.classes.dropActive)},onDrop:function(e){o(e.dataTransfer,n).then(function(){t(q,n)},function(){l.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.","error")})}});return h.addDisposer(function(){n.dispose()}),qq(e).hasAttribute(d)&&qq(e).hide(),p.push(n),n}function s(e){var t;return qq.each(e.dataTransfer.types,function(e,n){if("Files"===n)return t=!0,!1}),t}function a(e){return qq.firefox()?!e.relatedTarget:qq.safari()?e.x<0||e.y<0:0===e.x&&0===e.y}function u(){var e=l.dropZoneElements,t=function(){setTimeout(function(){qq.each(e,function(e,t){qq(t).hasAttribute(d)&&qq(t).hide(),qq(t).removeClass(l.classes.dropActive)})},10)};qq.each(e,function(t,n){var i=r(n);e.length&&qq.supportedFeatures.fileDrop&&h.attach(document,"dragenter",function(t){!i.dropDisabled()&&s(t)&&qq.each(e,function(e,t){t instanceof HTMLElement&&qq(t).hasAttribute(d)&&qq(t).css({display:"block"})})})}),h.attach(document,"dragleave",function(e){a(e)&&t()}),h.attach(qq(document).children()[0],"mouseenter",function(e){t()}),h.attach(document,"drop",function(e){e.preventDefault(),t()}),h.attach(document,c,t)}var l,c="qq-hidezones",d="qq-hide-dropzone",p=[],q=[],h=new qq.DisposeSupport;l={dropZoneElements:[],allowMultipleItems:!0,classes:{dropActive:null},callbacks:new qq.DragAndDrop.callbacks},qq.extend(l,e,!0),u(),qq.extend(this,{setupExtraDropzone:function(e){l.dropZoneElements.push(e),r(e)},removeDropzone:function(e){var t,n=l.dropZoneElements;for(t in n)if(n[t]===e)return n.splice(t,1)},dispose:function(){h.dispose(),qq.each(p,function(e,t){t.dispose()})}})},qq.DragAndDrop.callbacks=function(){"use strict";return{processingDroppedFiles:function(){},processingDroppedFilesComplete:function(e,t){},dropError:function(e,t){qq.log("Drag & drop error code '"+e+" with these specifics: '"+t+"'","error")},dropLog:function(e,t){qq.log(e,t)}}},qq.UploadDropZone=function(e){"use strict";function t(){return qq.safari()||qq.firefox()&&qq.windows()}function n(e){c||(t?d.attach(document,"dragover",function(e){e.preventDefault()}):d.attach(document,"dragover",function(e){e.dataTransfer&&(e.dataTransfer.dropEffect="none",e.preventDefault())}),c=!0)}function i(e){if(!qq.supportedFeatures.fileDrop)return!1;var t,n=e.dataTransfer,i=qq.safari();return t=!(!qq.ie()||!qq.supportedFeatures.fileDrop)||"none"!==n.effectAllowed,n&&t&&(n.files||!i&&n.types.contains&&n.types.contains("Files"))}function o(e){return void 0!==e&&(l=e),l}function r(){function e(){t=document.createEvent("Event"),t.initEvent(a.HIDE_ZONES_EVENT_NAME,!0,!0)}var t;if(window.CustomEvent)try{t=new CustomEvent(a.HIDE_ZONES_EVENT_NAME)}catch(t){e()}else e();document.dispatchEvent(t)}function s(){d.attach(u,"dragover",function(e){if(i(e)){var t=qq.ie()&&qq.supportedFeatures.fileDrop?null:e.dataTransfer.effectAllowed;"move"===t||"linkMove"===t?e.dataTransfer.dropEffect="move":e.dataTransfer.dropEffect="copy",e.stopPropagation(),e.preventDefault()}}),d.attach(u,"dragenter",function(e){if(!o()){if(!i(e))return;a.onEnter(e)}}),d.attach(u,"dragleave",function(e){if(i(e)){a.onLeave(e);var t=document.elementFromPoint(e.clientX,e.clientY);qq(this).contains(t)||a.onLeaveNotDescendants(e)}}),d.attach(u,"drop",function(e){if(!o()){if(!i(e))return;e.preventDefault(),e.stopPropagation(),a.onDrop(e),r()}})}var a,u,l,c,d=new qq.DisposeSupport;a={element:null,onEnter:function(e){},onLeave:function(e){},onLeaveNotDescendants:function(e){},onDrop:function(e){}},qq.extend(a,e),u=a.element,n(),s(),qq.extend(this,{dropDisabled:function(e){return o(e)},dispose:function(){d.dispose()},getElement:function(){return u}})},function(){"use strict";qq.uiPublicApi={addInitialFiles:function(e){this._parent.prototype.addInitialFiles.apply(this,arguments),this._templating.addCacheToDom()},clearStoredFiles:function(){this._parent.prototype.clearStoredFiles.apply(this,arguments),this._templating.clearFiles()},addExtraDropzone:function(e){this._dnd&&this._dnd.setupExtraDropzone(e)},removeExtraDropzone:function(e){if(this._dnd)return this._dnd.removeDropzone(e)},getItemByFileId:function(e){if(!this._templating.isHiddenForever(e))return this._templating.getFileContainer(e)},reset:function(){this._parent.prototype.reset.apply(this,arguments),this._templating.reset(),!this._options.button&&this._templating.getButton()&&(this._defaultButtonId=this._createUploadButton({element:this._templating.getButton(),title:this._options.text.fileInputTitle}).getButtonId()),this._dnd&&(this._dnd.dispose(),this._dnd=this._setupDragAndDrop()),this._totalFilesInBatch=0,this._filesInBatchAddedToUi=0,this._setupClickAndEditEventHandlers()},setName:function(e,t){var n=this._options.formatFileName(t);this._parent.prototype.setName.apply(this,arguments),this._templating.updateFilename(e,n)},pauseUpload:function(e){var t=this._parent.prototype.pauseUpload.apply(this,arguments);return t&&this._templating.uploadPaused(e),t},continueUpload:function(e){var t=this._parent.prototype.continueUpload.apply(this,arguments);return t&&this._templating.uploadContinued(e),t},getId:function(e){return this._templating.getFileId(e)},getDropTarget:function(e){var t=this.getFile(e);return t.qqDropTarget}},qq.uiPrivateApi={_getButton:function(e){var t=this._parent.prototype._getButton.apply(this,arguments);return t||e===this._defaultButtonId&&(t=this._templating.getButton()),t},_removeFileItem:function(e){this._templating.removeFile(e)},_setupClickAndEditEventHandlers:function(){this._fileButtonsClickHandler=qq.FileButtonsClickHandler&&this._bindFileButtonsClickEvent(),this._focusinEventSupported=!qq.firefox(),this._isEditFilenameEnabled()&&(this._filenameClickHandler=this._bindFilenameClickEvent(),this._filenameInputFocusInHandler=this._bindFilenameInputFocusInEvent(),this._filenameInputFocusHandler=this._bindFilenameInputFocusEvent())},_setupDragAndDrop:function(){var e=this,t=this._options.dragAndDrop.extraDropzones,n=this._templating,i=n.getDropZone();return i&&t.push(i),new qq.DragAndDrop({dropZoneElements:t,allowMultipleItems:this._options.multiple,classes:{dropActive:this._options.classes.dropActive},callbacks:{processingDroppedFiles:function(){n.showDropProcessing()},processingDroppedFilesComplete:function(t,i){n.hideDropProcessing(),qq.each(t,function(e,t){t.qqDropTarget=i}),t.length&&e.addFiles(t,null,null)},dropError:function(t,n){e._itemError(t,n)},dropLog:function(t,n){e.log(t,n)}}})},_bindFileButtonsClickEvent:function(){var e=this;return new qq.FileButtonsClickHandler({templating:this._templating,log:function(t,n){e.log(t,n)},onDeleteFile:function(t){e.deleteFile(t)},onCancel:function(t){e.cancel(t)},onRetry:function(t){e.retry(t)},onPause:function(t){e.pauseUpload(t)},onContinue:function(t){e.continueUpload(t)},onGetName:function(t){return e.getName(t)}})},_isEditFilenameEnabled:function(){return this._templating.isEditFilenamePossible()&&!this._options.autoUpload&&qq.FilenameClickHandler&&qq.FilenameInputFocusHandler&&qq.FilenameInputFocusHandler},_filenameEditHandler:function(){var e=this,t=this._templating;return{templating:t,log:function(t,n){e.log(t,n)},onGetUploadStatus:function(t){return e.getUploads({id:t}).status},onGetName:function(t){return e.getName(t)},onSetName:function(t,n){e.setName(t,n)},onEditingStatusChange:function(e,n){var i=qq(t.getEditInput(e)),o=qq(t.getFileContainer(e));n?(i.addClass("qq-editing"),t.hideFilename(e),t.hideEditIcon(e)):(i.removeClass("qq-editing"),t.showFilename(e),t.showEditIcon(e)),o.addClass("qq-temp").removeClass("qq-temp")}}},_onUploadStatusChange:function(e,t,n){this._parent.prototype._onUploadStatusChange.apply(this,arguments),this._isEditFilenameEnabled()&&this._templating.getFileContainer(e)&&n!==qq.status.SUBMITTED&&(this._templating.markFilenameEditable(e),this._templating.hideEditIcon(e)),t===qq.status.UPLOAD_RETRYING&&n===qq.status.UPLOADING?(this._templating.hideRetry(e),this._templating.setStatusText(e),qq(this._templating.getFileContainer(e)).removeClass(this._classes.retrying)):n===qq.status.UPLOAD_FAILED&&this._templating.hidePause(e)},_bindFilenameInputFocusInEvent:function(){var e=qq.extend({},this._filenameEditHandler());return new qq.FilenameInputFocusInHandler(e)},_bindFilenameInputFocusEvent:function(){var e=qq.extend({},this._filenameEditHandler());return new qq.FilenameInputFocusHandler(e)},_bindFilenameClickEvent:function(){var e=qq.extend({},this._filenameEditHandler());return new qq.FilenameClickHandler(e)},_storeForLater:function(e){this._parent.prototype._storeForLater.apply(this,arguments),this._templating.hideSpinner(e)},_onAllComplete:function(e,t){this._parent.prototype._onAllComplete.apply(this,arguments),this._templating.resetTotalProgress()},_onSubmit:function(e,t){var n=this.getFile(e);n&&n.qqPath&&this._options.dragAndDrop.reportDirectoryPaths&&this._paramsStore.addReadOnly(e,{qqpath:n.qqPath}),this._parent.prototype._onSubmit.apply(this,arguments),this._addToList(e,t)},_onSubmitted:function(e){this._isEditFilenameEnabled()&&(this._templating.markFilenameEditable(e),this._templating.showEditIcon(e),this._focusinEventSupported||this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(e)))},_onProgress:function(e,t,n,i){this._parent.prototype._onProgress.apply(this,arguments),this._templating.updateProgress(e,n,i),0===i||100===Math.round(n/i*100)?(this._templating.hideCancel(e),this._templating.hidePause(e),this._templating.hideProgress(e),this._templating.setStatusText(e,this._options.text.waitingForResponse),this._displayFileSize(e)):this._displayFileSize(e,n,i)},_onTotalProgress:function(e,t){this._parent.prototype._onTotalProgress.apply(this,arguments),this._templating.updateTotalProgress(e,t)},_onComplete:function(e,t,n,i){function o(t){a&&(s.setStatusText(e),qq(a).removeClass(u._classes.retrying),s.hideProgress(e),u.getUploads({id:e}).status!==qq.status.UPLOAD_FAILED&&s.hideCancel(e),s.hideSpinner(e),t.success?u._markFileAsSuccessful(e):(qq(a).addClass(u._classes.fail),s.showCancel(e),s.isRetryPossible()&&!u._preventRetries[e]&&(qq(a).addClass(u._classes.retryable),s.showRetry(e)),u._controlFailureTextDisplay(e,t)))}var r=this._parent.prototype._onComplete.apply(this,arguments),s=this._templating,a=s.getFileContainer(e),u=this;return r instanceof qq.Promise?r.done(function(e){o(e)}):o(n),r},_markFileAsSuccessful:function(e){var t=this._templating;this._isDeletePossible()&&t.showDeleteButton(e),qq(t.getFileContainer(e)).addClass(this._classes.success),this._maybeUpdateThumbnail(e)},_onUploadPrep:function(e){this._parent.prototype._onUploadPrep.apply(this,arguments),this._templating.showSpinner(e)},_onUpload:function(e,t){var n=this._parent.prototype._onUpload.apply(this,arguments);return this._templating.showSpinner(e),n},_onUploadChunk:function(e,t){this._parent.prototype._onUploadChunk.apply(this,arguments),t.partIndex>0&&this._handler.isResumable(e)&&this._templating.allowPause(e)},_onCancel:function(e,t){this._parent.prototype._onCancel.apply(this,arguments),this._removeFileItem(e),0===this._getNotFinished()&&this._templating.resetTotalProgress()},_onBeforeAutoRetry:function(e){var t,n,i;this._parent.prototype._onBeforeAutoRetry.apply(this,arguments),this._showCancelLink(e),this._options.retry.showAutoRetryNote&&(t=this._autoRetries[e],n=this._options.retry.maxAutoAttempts,i=this._options.retry.autoRetryNote.replace(/\{retryNum\}/g,t),i=i.replace(/\{maxAuto\}/g,n),this._templating.setStatusText(e,i),qq(this._templating.getFileContainer(e)).addClass(this._classes.retrying))},_onBeforeManualRetry:function(e){return this._parent.prototype._onBeforeManualRetry.apply(this,arguments)?(this._templating.resetProgress(e),qq(this._templating.getFileContainer(e)).removeClass(this._classes.fail),this._templating.setStatusText(e),this._templating.showSpinner(e),this._showCancelLink(e),!0):(qq(this._templating.getFileContainer(e)).addClass(this._classes.retryable),this._templating.showRetry(e),!1)},_onSubmitDelete:function(e){var t=qq.bind(this._onSubmitDeleteSuccess,this);this._parent.prototype._onSubmitDelete.call(this,e,t)},_onSubmitDeleteSuccess:function(e,t,n){this._options.deleteFile.forceConfirm?this._showDeleteConfirm.apply(this,arguments):this._sendDeleteRequest.apply(this,arguments)},_onDeleteComplete:function(e,t,n){this._parent.prototype._onDeleteComplete.apply(this,arguments),this._templating.hideSpinner(e),n?(this._templating.setStatusText(e,this._options.deleteFile.deletingFailedText),this._templating.showDeleteButton(e)):this._removeFileItem(e)},_sendDeleteRequest:function(e,t,n){this._templating.hideDeleteButton(e),this._templating.showSpinner(e),this._templating.setStatusText(e,this._options.deleteFile.deletingStatusText),this._deleteHandler.sendDelete.apply(this,arguments)},_showDeleteConfirm:function(e,t,n){var i,o=this.getName(e),r=this._options.deleteFile.confirmMessage.replace(/\{filename\}/g,o),s=(this.getUuid(e),arguments),a=this;i=this._options.showConfirm(r),qq.isGenericPromise(i)?i.then(function(){a._sendDeleteRequest.apply(a,s)}):i!==!1&&a._sendDeleteRequest.apply(a,s)},_addToList:function(e,t,n){var i,o,r=0,s=this._handler.isProxied(e)&&this._options.scaling.hideScaled;this._options.display.prependFiles&&(this._totalFilesInBatch>1&&this._filesInBatchAddedToUi>0&&(r=this._filesInBatchAddedToUi-1),i={index:r}),n||(this._options.disableCancelForFormUploads&&!qq.supportedFeatures.ajaxUploading&&this._templating.disableCancel(),this._options.multiple||(o=this.getUploads({id:e}),this._handledProxyGroup=this._handledProxyGroup||o.proxyGroupId,o.proxyGroupId===this._handledProxyGroup&&o.proxyGroupId||(this._handler.cancelAll(),this._clearList(),this._handledProxyGroup=null))),n?(this._templating.addFileToCache(e,this._options.formatFileName(t),i,s),this._templating.updateThumbnail(e,this._thumbnailUrls[e],!0,this._options.thumbnails.customResizer)):(this._templating.addFile(e,this._options.formatFileName(t),i,s),this._templating.generatePreview(e,this.getFile(e),this._options.thumbnails.customResizer)),this._filesInBatchAddedToUi+=1,(n||this._options.display.fileSizeOnSubmit&&qq.supportedFeatures.ajaxUploading)&&this._displayFileSize(e)},_clearList:function(){this._templating.clearFiles(),this.clearStoredFiles()},_displayFileSize:function(e,t,n){var i=this.getSize(e),o=this._formatSize(i);i>=0&&(void 0!==t&&void 0!==n&&(o=this._formatProgress(t,n)),this._templating.updateSize(e,o))},_formatProgress:function(e,t){function n(e,t){i=i.replace(e,t)}var i=this._options.text.formatProgress;return n("{percent}",Math.round(e/t*100)),n("{total_size}",this._formatSize(t)),i},_controlFailureTextDisplay:function(e,t){var n,i,o;n=this._options.failedUploadTextDisplay.mode,i=this._options.failedUploadTextDisplay.responseProperty,"custom"===n?(o=t[i],o||(o=this._options.text.failUpload),this._templating.setStatusText(e,o),this._options.failedUploadTextDisplay.enableTooltip&&this._showTooltip(e,o)):"default"===n?this._templating.setStatusText(e,this._options.text.failUpload):"none"!==n&&this.log("failedUploadTextDisplay.mode value of '"+n+"' is not valid","warn")},_showTooltip:function(e,t){this._templating.getFileContainer(e).title=t},_showCancelLink:function(e){this._options.disableCancelForFormUploads&&!qq.supportedFeatures.ajaxUploading||this._templating.showCancel(e)},_itemError:function(e,t,n){var i=this._parent.prototype._itemError.apply(this,arguments);this._options.showMessage(i)},_batchError:function(e){this._parent.prototype._batchError.apply(this,arguments),this._options.showMessage(e)},_setupPastePrompt:function(){var e=this;this._options.callbacks.onPasteReceived=function(){var t=e._options.paste.namePromptMessage,n=e._options.paste.defaultName;return e._options.showPrompt(t,n)}},_fileOrBlobRejected:function(e,t){this._totalFilesInBatch-=1,this._parent.prototype._fileOrBlobRejected.apply(this,arguments)},_prepareItemsForUpload:function(e,t,n){this._totalFilesInBatch=e.length,this._filesInBatchAddedToUi=0,this._parent.prototype._prepareItemsForUpload.apply(this,arguments)},_maybeUpdateThumbnail:function(e){var t=this._thumbnailUrls[e],n=this.getUploads({id:e}).status;n===qq.status.DELETED||!t&&!this._options.thumbnails.placeholders.waitUntilResponse&&qq.supportedFeatures.imagePreviews||this._templating.updateThumbnail(e,t,this._options.thumbnails.customResizer)},_addCannedFile:function(e){var t=this._parent.prototype._addCannedFile.apply(this,arguments);return this._addToList(t,this.getName(t),!0),this._templating.hideSpinner(t),this._templating.hideCancel(t),this._markFileAsSuccessful(t),t},_setSize:function(e,t){this._parent.prototype._setSize.apply(this,arguments),this._templating.updateSize(e,this._formatSize(t))},_sessionRequestComplete:function(){this._templating.addCacheToDom(),this._parent.prototype._sessionRequestComplete.apply(this,arguments)}}}(),qq.FineUploader=function(e,t){"use strict";var n=this;this._parent=t?qq[t].FineUploaderBasic:qq.FineUploaderBasic,this._parent.apply(this,arguments),qq.extend(this._options,{element:null,button:null,listElement:null,dragAndDrop:{extraDropzones:[],reportDirectoryPaths:!1},text:{formatProgress:"{percent}% of {total_size}",failUpload:"Upload failed",waitingForResponse:"Processing...",paused:"Paused"},template:"qq-template",classes:{retrying:"qq-upload-retrying",retryable:"qq-upload-retryable",success:"qq-upload-success",fail:"qq-upload-fail",editable:"qq-editable",hide:"qq-hide",dropActive:"qq-upload-drop-area-active"},failedUploadTextDisplay:{mode:"default",responseProperty:"error",enableTooltip:!0},messages:{tooManyFilesError:"You may only drop one file",unsupportedBrowser:"Unrecoverable error - this browser does not permit file uploading of any kind."},retry:{showAutoRetryNote:!0,autoRetryNote:"Retrying {retryNum}/{maxAuto}..."},deleteFile:{forceConfirm:!1,confirmMessage:"Are you sure you want to delete {filename}?",deletingStatusText:"Deleting...",deletingFailedText:"Delete failed"},display:{fileSizeOnSubmit:!1,prependFiles:!1},paste:{promptForName:!1,namePromptMessage:"Please name this image"},thumbnails:{customResizer:null,maxCount:0,placeholders:{waitUntilResponse:!1,notAvailablePath:null,waitingPath:null},timeBetweenThumbs:750},scaling:{hideScaled:!1},showMessage:function(e){return n._templating.hasDialog("alert")?n._templating.showDialog("alert",e):void setTimeout(function(){window.alert(e)},0)},showConfirm:function(e){return n._templating.hasDialog("confirm")?n._templating.showDialog("confirm",e):window.confirm(e)},showPrompt:function(e,t){return n._templating.hasDialog("prompt")?n._templating.showDialog("prompt",e,t):window.prompt(e,t)}},!0),qq.extend(this._options,e,!0),this._templating=new qq.Templating({log:qq.bind(this.log,this),templateIdOrEl:this._options.template,containerEl:this._options.element,fileContainerEl:this._options.listElement,button:this._options.button,imageGenerator:this._imageGenerator,classes:{hide:this._options.classes.hide,editable:this._options.classes.editable},limits:{maxThumbs:this._options.thumbnails.maxCount,timeBetweenThumbs:this._options.thumbnails.timeBetweenThumbs},placeholders:{waitUntilUpdate:this._options.thumbnails.placeholders.waitUntilResponse,thumbnailNotAvailable:this._options.thumbnails.placeholders.notAvailablePath,waitingForThumbnail:this._options.thumbnails.placeholders.waitingPath},text:this._options.text}),this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari()?this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari):!qq.supportedFeatures.uploading||this._options.cors.expected&&!qq.supportedFeatures.uploadCors?this._templating.renderFailure(this._options.messages.unsupportedBrowser):(this._wrapCallbacks(),this._templating.render(),this._classes=this._options.classes,!this._options.button&&this._templating.getButton()&&(this._defaultButtonId=this._createUploadButton({element:this._templating.getButton(),title:this._options.text.fileInputTitle}).getButtonId()),this._setupClickAndEditEventHandlers(),qq.DragAndDrop&&qq.supportedFeatures.fileDrop&&(this._dnd=this._setupDragAndDrop()),this._options.paste.targetElement&&this._options.paste.promptForName&&(qq.PasteSupport?this._setupPastePrompt():this.log("Paste support module not found.","error")),this._totalFilesInBatch=0,this._filesInBatchAddedToUi=0)},qq.extend(qq.FineUploader.prototype,qq.basePublicApi),qq.extend(qq.FineUploader.prototype,qq.basePrivateApi),qq.extend(qq.FineUploader.prototype,qq.uiPublicApi),qq.extend(qq.FineUploader.prototype,qq.uiPrivateApi),qq.Templating=function(e){"use strict";var t,n,i,o,r,s,a,u,l="qq-file-id",c="qq-file-id-",d="qq-max-size",p="qq-server-scale",q="qq-hide-dropzone",h="qq-drop-area-text",f="qq-in-progress",m="qq-hidden-forever",g={content:document.createDocumentFragment(),map:{}},_=!1,v=0,b=!1,S=[],y=-1,C={log:null,limits:{maxThumbs:0,timeBetweenThumbs:750},templateIdOrEl:"qq-template",containerEl:null,fileContainerEl:null,button:null,imageGenerator:null,classes:{hide:"qq-hide",editable:"qq-editable"},placeholders:{waitUntilUpdate:!1,thumbnailNotAvailable:null,waitingForThumbnail:null},text:{paused:"Paused"}},w={button:"qq-upload-button-selector",alertDialog:"qq-alert-dialog-selector",dialogCancelButton:"qq-cancel-button-selector",confirmDialog:"qq-confirm-dialog-selector",dialogMessage:"qq-dialog-message-selector",dialogOkButton:"qq-ok-button-selector",promptDialog:"qq-prompt-dialog-selector",uploader:"qq-uploader-selector",drop:"qq-upload-drop-area-selector",list:"qq-upload-list-selector",progressBarContainer:"qq-progress-bar-container-selector",progressBar:"qq-progress-bar-selector",totalProgressBarContainer:"qq-total-progress-bar-container-selector",totalProgressBar:"qq-total-progress-bar-selector",file:"qq-upload-file-selector",spinner:"qq-upload-spinner-selector",size:"qq-upload-size-selector",cancel:"qq-upload-cancel-selector",pause:"qq-upload-pause-selector",continueButton:"qq-upload-continue-selector",deleteButton:"qq-upload-delete-selector",retry:"qq-upload-retry-selector",statusText:"qq-upload-status-text-selector",editFilenameInput:"qq-edit-filename-selector",editNameIcon:"qq-edit-filename-icon-selector",dropText:"qq-upload-drop-area-text-selector",dropProcessing:"qq-drop-processing-selector",dropProcessingSpinner:"qq-drop-processing-spinner-selector",thumbnail:"qq-thumbnail-selector"},x={},E=new qq.Promise,P=new qq.Promise,F=function(){var e=C.placeholders.thumbnailNotAvailable,n=C.placeholders.waitingForThumbnail,i={maxSize:y,scale:u};a&&(e?C.imageGenerator.generate(e,new Image,i).then(function(e){E.success(e)},function(){E.failure(),t("Problem loading 'not available' placeholder image at "+e,"error")}):E.failure(),n?C.imageGenerator.generate(n,new Image,i).then(function(e){P.success(e)},function(){P.failure(),t("Problem loading 'waiting for thumbnail' placeholder image at "+n,"error")}):P.failure())},A=function(e){var t=new qq.Promise;return P.then(function(n){K(n,e),e.src?t.success():(e.src=n.src,e.onload=function(){e.onload=null,te(e),t.success()})},function(){W(e),t.success()}),t},T=function(e,n,i){var o=X(e);return t("Generating new thumbnail for "+e),n.qqThumbnailId=e,C.imageGenerator.generate(n,o,i).then(function(){v++,te(o),x[e].success()},function(){x[e].failure(),C.placeholders.waitUntilUpdate||J(e,o)})},I=function(){if(S.length){b=!0;var e=S.shift();e.update?$(e):Z(e)}else b=!1},R=function(e){return G(H(e),w.cancel)},U=function(e){return G(H(e),w.continueButton)},D=function(e){return G(r,w[e+"Dialog"])},k=function(e){return G(H(e),w.deleteButton)},B=function(){return G(r,w.dropProcessing)},N=function(e){return G(H(e),w.editNameIcon)},H=function(e){return g.map[e]||qq(s).getFirstByClass(c+e)},O=function(e){return G(H(e),w.file)},M=function(e){return G(H(e),w.pause)},z=function(e){return null==e?G(r,w.totalProgressBarContainer)||G(r,w.totalProgressBar):G(H(e),w.progressBarContainer)||G(H(e),w.progressBar)},L=function(e){return G(H(e),w.retry)},j=function(e){return G(H(e),w.size)},V=function(e){return G(H(e),w.spinner)},G=function(e,t){return e&&qq(e).getFirstByClass(t)},X=function(e){return a&&G(H(e),w.thumbnail)},W=function(e){e&&qq(e).addClass(C.classes.hide)},K=function(e,t){
+var n=e.style.maxWidth,i=e.style.maxHeight;i&&n&&!t.style.maxWidth&&!t.style.maxHeight&&qq(t).css({maxWidth:n,maxHeight:i})},J=function(e,t){var n=x[e]||(new qq.Promise).failure(),i=new qq.Promise;return E.then(function(e){n.then(function(){i.success()},function(){K(e,t),t.onload=function(){t.onload=null,i.success()},t.src=e.src,te(t)})}),i},Y=function(){var e,o,r,s,l,c,f,m,g,_,v;if(t("Parsing template"),null==C.templateIdOrEl)throw new Error("You MUST specify either a template element or ID!");if(qq.isString(C.templateIdOrEl)){if(e=document.getElementById(C.templateIdOrEl),null===e)throw new Error(qq.format("Cannot find template script at ID '{}'!",C.templateIdOrEl));o=e.innerHTML}else{if(void 0===C.templateIdOrEl.innerHTML)throw new Error("You have specified an invalid value for the template option! It must be an ID or an Element.");o=C.templateIdOrEl.innerHTML}if(o=qq.trimStr(o),s=document.createElement("div"),s.appendChild(qq.toElement(o)),v=qq(s).getFirstByClass(w.uploader),C.button&&(c=qq(s).getFirstByClass(w.button),c&&qq(c).remove()),qq.DragAndDrop&&qq.supportedFeatures.fileDrop||(g=qq(s).getFirstByClass(w.dropProcessing),g&&qq(g).remove()),f=qq(s).getFirstByClass(w.drop),f&&!qq.DragAndDrop&&(t("DnD module unavailable.","info"),qq(f).remove()),qq.supportedFeatures.fileDrop?qq(v).hasAttribute(h)&&f&&(_=qq(f).getFirstByClass(w.dropText),_&&qq(_).remove()):(v.removeAttribute(h),f&&qq(f).hasAttribute(q)&&qq(f).css({display:"none"})),m=qq(s).getFirstByClass(w.thumbnail),a?m&&(y=parseInt(m.getAttribute(d)),y=y>0?y:null,u=qq(m).hasAttribute(p)):m&&qq(m).remove(),a=a&&m,n=qq(s).getByClass(w.editFilenameInput).length>0,i=qq(s).getByClass(w.retry).length>0,r=qq(s).getFirstByClass(w.list),null==r)throw new Error("Could not find the file list container in the template!");return l=r.innerHTML,r.innerHTML="",s.getElementsByTagName("DIALOG").length&&document.createElement("dialog"),t("Template parsing complete"),{template:qq.trimStr(s.innerHTML),fileTemplate:qq.trimStr(l)}},Q=function(e,t,n){var i=n,o=i.firstChild;t>0&&(o=qq(i).children()[t].nextSibling),i.insertBefore(e,o)},Z=function(e){var t=e.id,n=e.optFileOrBlob,i=n&&n.qqThumbnailId,o=X(t),r={customResizeFunction:e.customResizeFunction,maxSize:y,orient:!0,scale:!0};qq.supportedFeatures.imagePreviews?o?C.limits.maxThumbs&&C.limits.maxThumbs<=v?(J(t,o),I()):A(o).done(function(){x[t]=new qq.Promise,x[t].done(function(){setTimeout(I,C.limits.timeBetweenThumbs)}),null!=i?ne(t,i):T(t,n,r)}):I():o&&(A(o),I())},$=function(e){var t=e.id,n=e.thumbnailUrl,i=e.showWaitingImg,o=X(t),r={customResizeFunction:e.customResizeFunction,scale:u,maxSize:y};if(o)if(n){if(!(C.limits.maxThumbs&&C.limits.maxThumbs<=v))return i&&A(o),C.imageGenerator.generate(n,o,r).then(function(){te(o),v++,setTimeout(I,C.limits.timeBetweenThumbs)},function(){J(t,o),setTimeout(I,C.limits.timeBetweenThumbs)});J(t,o),I()}else J(t,o),I()},ee=function(e,t){var n=z(e),i=null==e?w.totalProgressBar:w.progressBar;n&&!qq(n).hasClass(i)&&(n=qq(n).getFirstByClass(i)),n&&(qq(n).css({width:t+"%"}),n.setAttribute("aria-valuenow",t))},te=function(e){e&&qq(e).removeClass(C.classes.hide)},ne=function(e,n){var i=X(e),o=X(n);t(qq.format("ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.",e,n,n)),x[n].then(function(){v++,x[e].success(),t(qq.format("Now using previously generated thumbnail created for ID {} on ID {}.",n,e)),i.src=o.src,te(i)},function(){x[e].failure(),C.placeholders.waitUntilUpdate||J(e,i)})};qq.extend(C,e),t=C.log,qq.supportedFeatures.imagePreviews||(C.limits.timeBetweenThumbs=0,C.limits.maxThumbs=0),r=C.containerEl,a=void 0!==C.imageGenerator,o=Y(),F(),qq.extend(this,{render:function(){t("Rendering template in DOM."),v=0,r.innerHTML=o.template,W(B()),this.hideTotalProgress(),s=C.fileContainerEl||G(r,w.list),t("Template rendering complete")},renderFailure:function(e){var t=qq.toElement(e);r.innerHTML="",r.appendChild(t)},reset:function(){this.render()},clearFiles:function(){s.innerHTML=""},disableCancel:function(){_=!0},addFile:function(e,t,n,i,a){var u,d=qq.toElement(o.fileTemplate),p=G(d,w.file),q=G(r,w.uploader),f=a?g.content:s;a&&(g.map[e]=d),qq(d).addClass(c+e),q.removeAttribute(h),p&&(qq(p).setText(t),p.setAttribute("title",t)),d.setAttribute(l,e),n?Q(d,n.index,f):f.appendChild(d),i?(d.style.display="none",qq(d).addClass(m)):(W(z(e)),W(j(e)),W(k(e)),W(L(e)),W(M(e)),W(U(e)),_&&this.hideCancel(e),u=X(e),u&&!u.src&&P.then(function(e){u.src=e.src,e.style.maxHeight&&e.style.maxWidth&&qq(u).css({maxHeight:e.style.maxHeight,maxWidth:e.style.maxWidth}),te(u)}))},addFileToCache:function(e,t,n,i){this.addFile(e,t,n,i,!0)},addCacheToDom:function(){s.appendChild(g.content),g.content=document.createDocumentFragment(),g.map={}},removeFile:function(e){qq(H(e)).remove()},getFileId:function(e){var t=e;if(t){for(;null==t.getAttribute(l);)t=t.parentNode;return parseInt(t.getAttribute(l))}},getFileList:function(){return s},markFilenameEditable:function(e){var t=O(e);t&&qq(t).addClass(C.classes.editable)},updateFilename:function(e,t){var n=O(e);n&&(qq(n).setText(t),n.setAttribute("title",t))},hideFilename:function(e){W(O(e))},showFilename:function(e){te(O(e))},isFileName:function(e){return qq(e).hasClass(w.file)},getButton:function(){return C.button||G(r,w.button)},hideDropProcessing:function(){W(B())},showDropProcessing:function(){te(B())},getDropZone:function(){return G(r,w.drop)},isEditFilenamePossible:function(){return n},hideRetry:function(e){W(L(e))},isRetryPossible:function(){return i},showRetry:function(e){te(L(e))},getFileContainer:function(e){return H(e)},showEditIcon:function(e){var t=N(e);t&&qq(t).addClass(C.classes.editable)},isHiddenForever:function(e){return qq(H(e)).hasClass(m)},hideEditIcon:function(e){var t=N(e);t&&qq(t).removeClass(C.classes.editable)},isEditIcon:function(e){return qq(e).hasClass(w.editNameIcon,!0)},getEditInput:function(e){return G(H(e),w.editFilenameInput)},isEditInput:function(e){return qq(e).hasClass(w.editFilenameInput,!0)},updateProgress:function(e,t,n){var i,o=z(e);o&&n>0&&(i=Math.round(t/n*100),100===i?W(o):te(o),ee(e,i))},updateTotalProgress:function(e,t){this.updateProgress(null,e,t)},hideProgress:function(e){var t=z(e);t&&W(t)},hideTotalProgress:function(){this.hideProgress()},resetProgress:function(e){ee(e,0),this.hideTotalProgress(e)},resetTotalProgress:function(){this.resetProgress()},showCancel:function(e){if(!_){var t=R(e);t&&qq(t).removeClass(C.classes.hide)}},hideCancel:function(e){W(R(e))},isCancel:function(e){return qq(e).hasClass(w.cancel,!0)},allowPause:function(e){te(M(e)),W(U(e))},uploadPaused:function(e){this.setStatusText(e,C.text.paused),this.allowContinueButton(e),W(V(e))},hidePause:function(e){W(M(e))},isPause:function(e){return qq(e).hasClass(w.pause,!0)},isContinueButton:function(e){return qq(e).hasClass(w.continueButton,!0)},allowContinueButton:function(e){te(U(e)),W(M(e))},uploadContinued:function(e){this.setStatusText(e,""),this.allowPause(e),te(V(e))},showDeleteButton:function(e){te(k(e))},hideDeleteButton:function(e){W(k(e))},isDeleteButton:function(e){return qq(e).hasClass(w.deleteButton,!0)},isRetry:function(e){return qq(e).hasClass(w.retry,!0)},updateSize:function(e,t){var n=j(e);n&&(te(n),qq(n).setText(t))},setStatusText:function(e,t){var n=G(H(e),w.statusText);n&&(null==t?qq(n).clearText():qq(n).setText(t))},hideSpinner:function(e){qq(H(e)).removeClass(f),W(V(e))},showSpinner:function(e){qq(H(e)).addClass(f),te(V(e))},generatePreview:function(e,t,n){this.isHiddenForever(e)||(S.push({id:e,customResizeFunction:n,optFileOrBlob:t}),!b&&I())},updateThumbnail:function(e,t,n,i){this.isHiddenForever(e)||(S.push({customResizeFunction:i,update:!0,id:e,thumbnailUrl:t,showWaitingImg:n}),!b&&I())},hasDialog:function(e){return qq.supportedFeatures.dialogElement&&!!D(e)},showDialog:function(e,t,n){var i=D(e),o=G(i,w.dialogMessage),r=i.getElementsByTagName("INPUT")[0],s=G(i,w.dialogCancelButton),a=G(i,w.dialogOkButton),u=new qq.Promise,l=function(){s.removeEventListener("click",c),a&&a.removeEventListener("click",d),u.failure()},c=function(){s.removeEventListener("click",c),i.close()},d=function(){i.removeEventListener("close",l),a.removeEventListener("click",d),i.close(),u.success(r&&r.value)};return i.addEventListener("close",l),s.addEventListener("click",c),a&&a.addEventListener("click",d),r&&(r.value=n),o.textContent=t,i.showModal(),u}})},qq.UiEventHandler=function(e,t){"use strict";function n(e){i.attach(e,o.eventType,function(e){e=e||window.event;var t=e.target||e.srcElement;o.onHandled(t,e)})}var i=new qq.DisposeSupport,o={eventType:"click",attachTo:null,onHandled:function(e,t){}};qq.extend(this,{addHandler:function(e){n(e)},dispose:function(){i.dispose()}}),qq.extend(t,{getFileIdFromItem:function(e){return e.qqFileId},getDisposeSupport:function(){return i}}),qq.extend(o,e),o.attachTo&&n(o.attachTo)},qq.FileButtonsClickHandler=function(e){"use strict";function t(e,t){qq.each(o,function(n,o){var r,s=n.charAt(0).toUpperCase()+n.slice(1);if(i.templating["is"+s](e))return r=i.templating.getFileId(e),qq.preventDefault(t),i.log(qq.format("Detected valid file button click event on file '{}', ID: {}.",i.onGetName(r),r)),o(r),!1})}var n={},i={templating:null,log:function(e,t){},onDeleteFile:function(e){},onCancel:function(e){},onRetry:function(e){},onPause:function(e){},onContinue:function(e){},onGetName:function(e){}},o={cancel:function(e){i.onCancel(e)},retry:function(e){i.onRetry(e)},deleteButton:function(e){i.onDeleteFile(e)},pause:function(e){i.onPause(e)},continueButton:function(e){i.onContinue(e)}};qq.extend(i,e),i.eventType="click",i.onHandled=t,i.attachTo=i.templating.getFileList(),qq.extend(this,new qq.UiEventHandler(i,n))},qq.FilenameClickHandler=function(e){"use strict";function t(e,t){if(i.templating.isFileName(e)||i.templating.isEditIcon(e)){var o=i.templating.getFileId(e),r=i.onGetUploadStatus(o);r===qq.status.SUBMITTED&&(i.log(qq.format("Detected valid filename click event on file '{}', ID: {}.",i.onGetName(o),o)),qq.preventDefault(t),n.handleFilenameEdit(o,e,!0))}}var n={},i={templating:null,log:function(e,t){},classes:{file:"qq-upload-file",editNameIcon:"qq-edit-filename-icon"},onGetUploadStatus:function(e){},onGetName:function(e){}};qq.extend(i,e),i.eventType="click",i.onHandled=t,qq.extend(this,new qq.FilenameEditHandler(i,n))},qq.FilenameInputFocusInHandler=function(e,t){"use strict";function n(e,n){if(i.templating.isEditInput(e)){var o=i.templating.getFileId(e),r=i.onGetUploadStatus(o);r===qq.status.SUBMITTED&&(i.log(qq.format("Detected valid filename input focus event on file '{}', ID: {}.",i.onGetName(o),o)),t.handleFilenameEdit(o,e))}}var i={templating:null,onGetUploadStatus:function(e){},log:function(e,t){}};t||(t={}),i.eventType="focusin",i.onHandled=n,qq.extend(i,e),qq.extend(this,new qq.FilenameEditHandler(i,t))},qq.FilenameInputFocusHandler=function(e){"use strict";e.eventType="focus",e.attachTo=null,qq.extend(this,new qq.FilenameInputFocusInHandler(e,{}))},qq.FilenameEditHandler=function(e,t){"use strict";function n(e){var t=a.onGetName(e),n=t.lastIndexOf(".");return n>0&&(t=t.substr(0,n)),t}function i(e){var t=a.onGetName(e);return qq.getExtension(t)}function o(e,t){var n,o=e.value;void 0!==o&&qq.trimStr(o).length>0&&(n=i(t),void 0!==n&&(o=o+"."+n),a.onSetName(t,o)),a.onEditingStatusChange(t,!1)}function r(e,n){t.getDisposeSupport().attach(e,"blur",function(){o(e,n)})}function s(e,n){t.getDisposeSupport().attach(e,"keyup",function(t){var i=t.keyCode||t.which;13===i&&o(e,n)})}var a={templating:null,log:function(e,t){},onGetUploadStatus:function(e){},onGetName:function(e){},onSetName:function(e,t){},onEditingStatusChange:function(e,t){}};qq.extend(a,e),a.attachTo=a.templating.getFileList(),qq.extend(this,new qq.UiEventHandler(a,t)),qq.extend(t,{handleFilenameEdit:function(e,t,i){var o=a.templating.getEditInput(e);a.onEditingStatusChange(e,!0),o.value=n(e),i&&o.focus(),r(o,e),s(o,e)}})},qq.CryptoJS=function(e,t){var n={},i=n.lib={},o=i.Base=function(){function e(){}return{extend:function(t){e.prototype=this;var n=new e;return t&&n.mixIn(t),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var e=this.extend();return e.init.apply(e,arguments),e},init:function(){},mixIn:function(e){for(var t in e)e.hasOwnProperty(t)&&(this[t]=e[t]);e.hasOwnProperty("toString")&&(this.toString=e.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),r=i.WordArray=o.extend({init:function(e,n){e=this.words=e||[],n!=t?this.sigBytes=n:this.sigBytes=4*e.length},toString:function(e){return(e||a).stringify(this)},concat:function(e){var t=this.words,n=e.words,i=this.sigBytes,o=e.sigBytes;if(this.clamp(),i%4)for(var r=0;r>>2]>>>24-r%4*8&255;t[i+r>>>2]|=s<<24-(i+r)%4*8}else if(n.length>65535)for(var r=0;r>>2]=n[r>>>2];else t.push.apply(t,n);return this.sigBytes+=o,this},clamp:function(){var t=this.words,n=this.sigBytes;t[n>>>2]&=4294967295<<32-n%4*8,t.length=e.ceil(n/4)},clone:function(){var e=o.clone.call(this);return e.words=this.words.slice(0),e},random:function(t){for(var n=[],i=0;i>>2]>>>24-o%4*8&255;i.push((r>>>4).toString(16)),i.push((15&r).toString(16))}return i.join("")},parse:function(e){for(var t=e.length,n=[],i=0;i>>3]|=parseInt(e.substr(i,2),16)<<24-i%8*4;return new r.init(n,t/2)}},u=s.Latin1={stringify:function(e){for(var t=e.words,n=e.sigBytes,i=[],o=0;o>>2]>>>24-o%4*8&255;i.push(String.fromCharCode(r))}return i.join("")},parse:function(e){for(var t=e.length,n=[],i=0;i>>2]|=(255&e.charCodeAt(i))<<24-i%4*8;return new r.init(n,t)}},l=s.Utf8={stringify:function(e){try{return decodeURIComponent(escape(u.stringify(e)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(e){return u.parse(unescape(encodeURIComponent(e)))}},c=i.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new r.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=l.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(t){var n=this._data,i=n.words,o=n.sigBytes,s=this.blockSize,a=4*s,u=o/a;u=t?e.ceil(u):e.max((0|u)-this._minBufferSize,0);var l=u*s,c=e.min(4*l,o);if(l){for(var d=0;d>>2]>>>24-r%4*8&255,a=t[r+1>>>2]>>>24-(r+1)%4*8&255,u=t[r+2>>>2]>>>24-(r+2)%4*8&255,l=s<<16|a<<8|u,c=0;c<4&&r+.75*c>>6*(3-c)&63));var d=i.charAt(64);if(d)for(;o.length%4;)o.push(d);return o.join("")},parse:function(e){var t=e.length,i=this._map,o=i.charAt(64);if(o){var r=e.indexOf(o);r!=-1&&(t=r)}for(var s=[],a=0,u=0;u>>6-u%4*2;s[a>>>2]|=(l|c)<<24-a%4*8,a++}return n.create(s,a)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}}(),function(){var e=qq.CryptoJS,t=e.lib,n=t.Base,i=e.enc,o=i.Utf8,r=e.algo;r.HMAC=n.extend({init:function(e,t){e=this._hasher=new e.init,"string"==typeof t&&(t=o.parse(t));var n=e.blockSize,i=4*n;t.sigBytes>i&&(t=e.finalize(t)),t.clamp();for(var r=this._oKey=t.clone(),s=this._iKey=t.clone(),a=r.words,u=s.words,l=0;l>>31}var d=(i<<5|i>>>27)+u+r[l];d+=l<20?(o&s|~o&a)+1518500249:l<40?(o^s^a)+1859775393:l<60?(o&s|o&a|s&a)-1894007588:(o^s^a)-899497514,u=a,a=s,s=o<<30|o>>>2,o=i,i=d}n[0]=n[0]+i|0,n[1]=n[1]+o|0,n[2]=n[2]+s|0,n[3]=n[3]+a|0,n[4]=n[4]+u|0},_doFinalize:function(){var e=this._data,t=e.words,n=8*this._nDataBytes,i=8*e.sigBytes;return t[i>>>5]|=128<<24-i%32,t[(i+64>>>9<<4)+14]=Math.floor(n/4294967296),t[(i+64>>>9<<4)+15]=n,e.sigBytes=4*t.length,this._process(),this._hash},clone:function(){var e=i.clone.call(this);return e._hash=this._hash.clone(),e}});e.SHA1=i._createHelper(s),e.HmacSHA1=i._createHmacHelper(s)}(),function(e){var t=qq.CryptoJS,n=t.lib,i=n.WordArray,o=n.Hasher,r=t.algo,s=[],a=[];!function(){function t(t){for(var n=e.sqrt(t),i=2;i<=n;i++)if(!(t%i))return!1;return!0}function n(e){return 4294967296*(e-(0|e))|0}for(var i=2,o=0;o<64;)t(i)&&(o<8&&(s[o]=n(e.pow(i,.5))),a[o]=n(e.pow(i,1/3)),o++),i++}();var u=[],l=r.SHA256=o.extend({_doReset:function(){this._hash=new i.init(s.slice(0))},_doProcessBlock:function(e,t){for(var n=this._hash.words,i=n[0],o=n[1],r=n[2],s=n[3],l=n[4],c=n[5],d=n[6],p=n[7],q=0;q<64;q++){if(q<16)u[q]=0|e[t+q];else{var h=u[q-15],f=(h<<25|h>>>7)^(h<<14|h>>>18)^h>>>3,m=u[q-2],g=(m<<15|m>>>17)^(m<<13|m>>>19)^m>>>10;u[q]=f+u[q-7]+g+u[q-16]}var _=l&c^~l&d,v=i&o^i&r^o&r,b=(i<<30|i>>>2)^(i<<19|i>>>13)^(i<<10|i>>>22),S=(l<<26|l>>>6)^(l<<21|l>>>11)^(l<<7|l>>>25),y=p+S+_+a[q]+u[q],C=b+v;p=d,d=c,c=l,l=s+y|0,s=r,r=o,o=i,i=y+C|0}n[0]=n[0]+i|0,n[1]=n[1]+o|0,n[2]=n[2]+r|0,n[3]=n[3]+s|0,n[4]=n[4]+l|0,n[5]=n[5]+c|0,n[6]=n[6]+d|0,n[7]=n[7]+p|0},_doFinalize:function(){var t=this._data,n=t.words,i=8*this._nDataBytes,o=8*t.sigBytes;return n[o>>>5]|=128<<24-o%32,n[(o+64>>>9<<4)+14]=e.floor(i/4294967296),n[(o+64>>>9<<4)+15]=i,t.sigBytes=4*n.length,this._process(),this._hash},clone:function(){var e=o.clone.call(this);return e._hash=this._hash.clone(),e}});t.SHA256=o._createHelper(l),t.HmacSHA256=o._createHmacHelper(l)}(Math),function(){if("function"==typeof ArrayBuffer){var e=qq.CryptoJS,t=e.lib,n=t.WordArray,i=n.init,o=n.init=function(e){if(e instanceof ArrayBuffer&&(e=new Uint8Array(e)),(e instanceof Int8Array||e instanceof Uint8ClampedArray||e instanceof Int16Array||e instanceof Uint16Array||e instanceof Int32Array||e instanceof Uint32Array||e instanceof Float32Array||e instanceof Float64Array)&&(e=new Uint8Array(e.buffer,e.byteOffset,e.byteLength)),e instanceof Uint8Array){for(var t=e.byteLength,n=[],o=0;o>>2]|=e[o]<<24-o%4*8;i.call(this,n,t)}else i.apply(this,arguments)};o.prototype=n}}(),qq.s3=qq.s3||{},qq.s3.util=qq.s3.util||function(){"use strict";return{ALGORITHM_PARAM_NAME:"x-amz-algorithm",AWS_PARAM_PREFIX:"x-amz-meta-",CREDENTIAL_PARAM_NAME:"x-amz-credential",DATE_PARAM_NAME:"x-amz-date",REDUCED_REDUNDANCY_PARAM_NAME:"x-amz-storage-class",REDUCED_REDUNDANCY_PARAM_VALUE:"REDUCED_REDUNDANCY",SERVER_SIDE_ENCRYPTION_PARAM_NAME:"x-amz-server-side-encryption",SERVER_SIDE_ENCRYPTION_PARAM_VALUE:"AES256",SESSION_TOKEN_PARAM_NAME:"x-amz-security-token",V4_ALGORITHM_PARAM_VALUE:"AWS4-HMAC-SHA256",V4_SIGNATURE_PARAM_NAME:"x-amz-signature",CASE_SENSITIVE_PARAM_NAMES:["Cache-Control","Content-Disposition","Content-Encoding","Content-MD5"],UNSIGNABLE_REST_HEADER_NAMES:["Cache-Control","Content-Disposition","Content-Encoding","Content-MD5"],UNPREFIXED_PARAM_NAMES:["Cache-Control","Content-Disposition","Content-Encoding","Content-MD5","x-amz-server-side-encryption-customer-algorithm","x-amz-server-side-encryption-customer-key","x-amz-server-side-encryption-customer-key-MD5"],getBucket:function(e){var t,n=[/^(?:https?:\/\/)?([a-z0-9.\-_]+)\.s3(?:-[a-z0-9\-]+)?\.amazonaws\.com/i,/^(?:https?:\/\/)?s3(?:-[a-z0-9\-]+)?\.amazonaws\.com\/([a-z0-9.\-_]+)/i,/^(?:https?:\/\/)?([a-z0-9.\-_]+)/i];return qq.each(n,function(n,i){var o=i.exec(e);if(o)return t=o[1],!1}),t},_getPrefixedParamName:function(e){return qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES,e)>=0?e:qq.s3.util.AWS_PARAM_PREFIX+e},getPolicy:function(e){var t={},n=[],i=e.bucket,o=e.date,r=e.clockDrift,s=e.key,a=e.accessKey,u=e.acl,l=e.type,c=e.expectedStatus,d=e.sessionToken,p=e.params,q=qq.s3.util.getSuccessRedirectAbsoluteUrl(e.successRedirectUrl),h=e.minFileSize,f=e.maxFileSize,m=e.reducedRedundancy,g=e.region,_=e.serverSideEncryption,v=e.signatureVersion;return t.expiration=qq.s3.util.getPolicyExpirationDate(o,r),n.push({acl:u}),n.push({bucket:i}),l&&n.push({"Content-Type":l}),c&&n.push({success_action_status:c.toString()}),q&&n.push({success_action_redirect:q}),m&&(n.push({}),n[n.length-1][qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]=qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE),d&&(n.push({}),n[n.length-1][qq.s3.util.SESSION_TOKEN_PARAM_NAME]=d),_&&(n.push({}),n[n.length-1][qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]=qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE),2===v?n.push({key:s}):4===v&&(n.push({}),n[n.length-1][qq.s3.util.ALGORITHM_PARAM_NAME]=qq.s3.util.V4_ALGORITHM_PARAM_VALUE,n.push({}),n[n.length-1].key=s,n.push({}),n[n.length-1][qq.s3.util.CREDENTIAL_PARAM_NAME]=qq.s3.util.getV4CredentialsString({date:o,key:a,region:g}),n.push({}),n[n.length-1][qq.s3.util.DATE_PARAM_NAME]=qq.s3.util.getV4PolicyDate(o,r)),qq.each(p,function(e,t){var i=qq.s3.util._getPrefixedParamName(e),o={};qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES,i)>=0?o[i]=t:o[i]=encodeURIComponent(t),n.push(o)}),t.conditions=n,qq.s3.util.enforceSizeLimits(t,h,f),t},refreshPolicyCredentials:function(e,t){var n=!1;qq.each(e.conditions,function(e,i){qq.each(i,function(e,o){e===qq.s3.util.SESSION_TOKEN_PARAM_NAME&&(i[e]=t,n=!0)})}),n||(e.conditions.push({}),e.conditions[e.conditions.length-1][qq.s3.util.SESSION_TOKEN_PARAM_NAME]=t)},generateAwsParams:function(e,t){var n,i={},o=e.params,r=new qq.Promise,s=e.sessionToken,a=e.clockDrift,u=e.type,l=e.key,c=e.accessKey,d=e.acl,p=e.expectedStatus,q=qq.s3.util.getSuccessRedirectAbsoluteUrl(e.successRedirectUrl),h=e.reducedRedundancy,f=e.region,m=e.serverSideEncryption,g=e.signatureVersion,_=new Date,v=e.log;return e.date=_,n=qq.s3.util.getPolicy(e),i.key=l,u&&(i["Content-Type"]=u),p&&(i.success_action_status=p),q&&(i.success_action_redirect=q),h&&(i[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]=qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE),m&&(i[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]=qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE),s&&(i[qq.s3.util.SESSION_TOKEN_PARAM_NAME]=s),i.acl=d,qq.each(o,function(e,t){var n=qq.s3.util._getPrefixedParamName(e);qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES,n)>=0?i[n]=t:i[n]=encodeURIComponent(t)}),2===g?i.AWSAccessKeyId=c:4===g&&(i[qq.s3.util.ALGORITHM_PARAM_NAME]=qq.s3.util.V4_ALGORITHM_PARAM_VALUE,i[qq.s3.util.CREDENTIAL_PARAM_NAME]=qq.s3.util.getV4CredentialsString({date:_,key:c,region:f}),i[qq.s3.util.DATE_PARAM_NAME]=qq.s3.util.getV4PolicyDate(_,a)),t(n).then(function(t,n,o){i.policy=t.policy,2===e.signatureVersion?(i.signature=t.signature,n&&(i.AWSAccessKeyId=n)):4===e.signatureVersion&&(i[qq.s3.util.V4_SIGNATURE_PARAM_NAME]=t.signature),o&&(i[qq.s3.util.SESSION_TOKEN_PARAM_NAME]=o),r.success(i)},function(e){e=e||"Can't continue further with request to S3 as we did not receive a valid signature and policy from the server.",v("Policy signing failed. "+e,"error"),r.failure(e)}),r},enforceSizeLimits:function(e,t,n){var i=t<0?0:t,o=n<=0?9007199254740992:n;(t>0||n>0)&&e.conditions.push(["content-length-range",i.toString(),o.toString()])},getPolicyExpirationDate:function(e,t){var n=new Date(e.getTime()+t);return qq.s3.util.getPolicyDate(n,5)},getCredentialsDate:function(e){return e.getUTCFullYear()+""+("0"+(e.getUTCMonth()+1)).slice(-2)+("0"+e.getUTCDate()).slice(-2)},getPolicyDate:function(e,t){var n,i,o=t||0;return e.setMinutes(e.getMinutes()+(o||0)),Date.prototype.toISOString?e.toISOString():(n=function(e){return i=String(e),1===i.length&&(i="0"+i),i},e.getUTCFullYear()+"-"+n(e.getUTCMonth()+1)+"-"+n(e.getUTCDate())+"T"+n(e.getUTCHours())+":"+n(e.getUTCMinutes())+":"+n(e.getUTCSeconds())+"."+String((e.getUTCMilliseconds()/1e3).toFixed(3)).slice(2,5)+"Z")},parseIframeResponse:function(e){var t=e.contentDocument||e.contentWindow.document,n=t.location.search,i=/bucket=(.+)&key=(.+)&etag=(.+)/.exec(n);if(i)return{bucket:i[1],key:i[2],etag:i[3].replace(/%22/g,"")}},getSuccessRedirectAbsoluteUrl:function(e){if(e){var t,n=document.createElement("div");return qq.ie7()?(n.innerHTML=" ",t=n.firstChild,t.href):(t=document.createElement("a"),t.href=e,t.href=t.href,t.href)}},getV4CredentialsString:function(e){return e.key+"/"+qq.s3.util.getCredentialsDate(e.date)+"/"+e.region+"/s3/aws4_request"},getV4PolicyDate:function(e,t){var n=new Date(e.getTime()+t);return qq.s3.util.getCredentialsDate(n)+"T"+("0"+n.getUTCHours()).slice(-2)+("0"+n.getUTCMinutes()).slice(-2)+("0"+n.getUTCSeconds()).slice(-2)+"Z"},encodeQueryStringParam:function(e){var t=encodeURIComponent(e);return t=t.replace(/[!'()]/g,escape),t=t.replace(/\*/g,"%2A"),t.replace(/%20/g,"+")},uriEscape:function(e){var t=encodeURIComponent(e);return t=t.replace(/[^A-Za-z0-9_.~\-%]+/g,escape),t=t.replace(/[*]/g,function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})},uriEscapePath:function(e){var t=[];return qq.each(e.split("/"),function(e,n){t.push(qq.s3.util.uriEscape(n))}),t.join("/")}}}(),function(){"use strict";qq.nonTraditionalBasePublicApi={setUploadSuccessParams:function(e,t){this._uploadSuccessParamsStore.set(e,t)},setUploadSuccessEndpoint:function(e,t){this._uploadSuccessEndpointStore.set(e,t)}},qq.nonTraditionalBasePrivateApi={_onComplete:function(e,t,n,i){var o,r,s=!!n.success,a=this,u=arguments,l=this._uploadSuccessEndpointStore.get(e),c=this._options.uploadSuccess.customHeaders,d=this._options.uploadSuccess.method,p=this._options.cors,q=new qq.Promise,h=this._uploadSuccessParamsStore.get(e),f=this._paramsStore.get(e),m=function(t){delete a._failedSuccessRequestCallbacks[e],qq.extend(n,t),qq.FineUploaderBasic.prototype._onComplete.apply(a,u),q.success(t)},g=function(r){var s=o;qq.extend(n,r),n&&n.reset&&(s=null),s?a._failedSuccessRequestCallbacks[e]=s:delete a._failedSuccessRequestCallbacks[e],a._onAutoRetry(e,t,n,i,s)||(qq.FineUploaderBasic.prototype._onComplete.apply(a,u),q.failure(r))};return s&&l?(r=new qq.UploadSuccessAjaxRequester({endpoint:l,method:d,customHeaders:c,cors:p,log:qq.bind(this.log,this)}),qq.extend(h,a._getEndpointSpecificParams(e,n,i),!0),f&&qq.extend(h,f,!0),o=qq.bind(function(){r.sendSuccessRequest(e,h).then(m,g)},a),o(),q):qq.FineUploaderBasic.prototype._onComplete.apply(this,arguments)},_manualRetry:function(e){var t=this._failedSuccessRequestCallbacks[e];return qq.FineUploaderBasic.prototype._manualRetry.call(this,e,t)}}}(),function(){"use strict";qq.s3.FineUploaderBasic=function(e){var t={request:{accessKey:null,clockDrift:0},objectProperties:{acl:"private",bucket:qq.bind(function(e){return qq.s3.util.getBucket(this.getEndpoint(e))},this),host:qq.bind(function(e){return/(?:http|https):\/\/(.+)(?:\/.+)?/.exec(this._endpointStore.get(e))[1]},this),key:"uuid",reducedRedundancy:!1,region:"us-east-1",serverSideEncryption:!1},credentials:{accessKey:null,secretKey:null,expiration:null,sessionToken:null},signature:{customHeaders:{},endpoint:null,version:2},uploadSuccess:{endpoint:null,method:"POST",params:{},customHeaders:{}},iframeSupport:{localBlankPagePath:null},chunking:{partSize:5242880},cors:{allowXdr:!0},callbacks:{onCredentialsExpired:function(){}}};qq.extend(t,e,!0),this.setCredentials(t.credentials,!0)||(this._currentCredentials.accessKey=t.request.accessKey),this._aclStore=this._createStore(t.objectProperties.acl),qq.FineUploaderBasic.call(this,t),this._uploadSuccessParamsStore=this._createStore(this._options.uploadSuccess.params),this._uploadSuccessEndpointStore=this._createStore(this._options.uploadSuccess.endpoint),this._failedSuccessRequestCallbacks={},this._cannedKeys={},this._cannedBuckets={},this._buckets={},this._hosts={}},qq.extend(qq.s3.FineUploaderBasic.prototype,qq.basePublicApi),qq.extend(qq.s3.FineUploaderBasic.prototype,qq.basePrivateApi),qq.extend(qq.s3.FineUploaderBasic.prototype,qq.nonTraditionalBasePublicApi),qq.extend(qq.s3.FineUploaderBasic.prototype,qq.nonTraditionalBasePrivateApi),qq.extend(qq.s3.FineUploaderBasic.prototype,{getBucket:function(e){return null==this._cannedBuckets[e]?this._buckets[e]:this._cannedBuckets[e]},getKey:function(e){return null==this._cannedKeys[e]?this._handler.getThirdPartyFileId(e):this._cannedKeys[e]},reset:function(){qq.FineUploaderBasic.prototype.reset.call(this),this._failedSuccessRequestCallbacks=[],this._buckets={},this._hosts={}},setCredentials:function(e,t){if(e&&e.secretKey){if(!e.accessKey)throw new qq.Error("Invalid credentials: no accessKey");if(!e.expiration)throw new qq.Error("Invalid credentials: no expiration");return this._currentCredentials=qq.extend({},e),qq.isString(e.expiration)&&(this._currentCredentials.expiration=new Date(e.expiration)),!0}if(!t)throw new qq.Error("Invalid credentials parameter!");this._currentCredentials={}},setAcl:function(e,t){this._aclStore.set(e,t)},_createUploadHandler:function(){var e=this,t={aclStore:this._aclStore,getBucket:qq.bind(this._determineBucket,this),getHost:qq.bind(this._determineHost,this),getKeyName:qq.bind(this._determineKeyName,this),iframeSupport:this._options.iframeSupport,objectProperties:this._options.objectProperties,signature:this._options.signature,clockDrift:this._options.request.clockDrift,validation:{minSizeLimit:this._options.validation.minSizeLimit,maxSizeLimit:this._options.validation.sizeLimit}};return qq.override(this._endpointStore,function(e){return{get:function(t){var n=e.get(t);return n.indexOf("http")<0?"http://"+n:n}}}),qq.override(this._paramsStore,function(e){return{get:function(t){var n=e.get(t),i={};return qq.each(n,function(e,t){var n=e;qq.indexOf(qq.s3.util.CASE_SENSITIVE_PARAM_NAMES,n)<0&&(n=n.toLowerCase()),i[n]=qq.isFunction(t)?t():t}),i}}}),t.signature.credentialsProvider={get:function(){return e._currentCredentials},onExpired:function(){var t=new qq.Promise,n=e._options.callbacks.onCredentialsExpired();return qq.isGenericPromise(n)?n.then(function(n){try{e.setCredentials(n),t.success()}catch(n){e.log("Invalid credentials returned from onCredentialsExpired callback! ("+n.message+")","error"),t.failure("onCredentialsExpired did not return valid credentials.")}},function(n){e.log("onCredentialsExpired callback indicated failure! ("+n+")","error"),t.failure("onCredentialsExpired callback failed.")}):(e.log("onCredentialsExpired callback did not return a promise!","error"),t.failure("Unexpected return value for onCredentialsExpired.")),t}},qq.FineUploaderBasic.prototype._createUploadHandler.call(this,t,"s3")},_determineObjectPropertyValue:function(e,t){var n=this._options.objectProperties[t],i=new qq.Promise,o=this;return qq.isFunction(n)?(n=n(e),qq.isGenericPromise(n)?i=n:i.success(n)):qq.isString(n)&&i.success(n),i.then(function(n){o["_"+t+"s"][e]=n},function(n){qq.log("Problem determining "+t+" for ID "+e+" ("+n+")","error")}),i},_determineBucket:function(e){return this._determineObjectPropertyValue(e,"bucket")},_determineHost:function(e){return this._determineObjectPropertyValue(e,"host");
+},_determineKeyName:function(e,t){var n=new qq.Promise,i=this._options.objectProperties.key,o=qq.getExtension(t),r=n.failure,s=function(e,t){var i=e;void 0!==t&&(i+="."+t),n.success(i)};switch(i){case"uuid":s(this.getUuid(e),o);break;case"filename":s(t);break;default:qq.isFunction(i)?this._handleKeynameFunction(i,e,s,r):(this.log(i+" is not a valid value for the s3.keyname option!","error"),r())}return n},_handleKeynameFunction:function(e,t,n,i){var o=this,r=function(e){n(e)},s=function(e){o.log(qq.format("Failed to retrieve key name for {}. Reason: {}",t,e||"null"),"error"),i(e)},a=e.call(this,t);qq.isGenericPromise(a)?a.then(r,s):null==a?s():r(a)},_getEndpointSpecificParams:function(e,t,n){var i={key:this.getKey(e),uuid:this.getUuid(e),name:this.getName(e),bucket:this.getBucket(e)};return n&&n.getResponseHeader("ETag")?i.etag=n.getResponseHeader("ETag"):t.etag&&(i.etag=t.etag),i},_onSubmitDelete:function(e,t){var n={key:this.getKey(e),bucket:this.getBucket(e)};return qq.FineUploaderBasic.prototype._onSubmitDelete.call(this,e,t,n)},_addCannedFile:function(e){var t;if(null==e.s3Key)throw new qq.Error("Did not find s3Key property in server session response. This is required!");return t=qq.FineUploaderBasic.prototype._addCannedFile.apply(this,arguments),this._cannedKeys[t]=e.s3Key,this._cannedBuckets[t]=e.s3Bucket,t}})}(),window.Uint8ClampedArray||(window.Uint8ClampedArray=function(){}),qq.s3.RequestSigner=function(e){"use strict";function t(e,t,n){var i,o,r=t.responseText,s=l[e],a=s.promise,u=s.signatureConstructor;if(delete l[e],r)try{o=qq.parseJson(r)}catch(e){c.log("Error attempting to parse signature response: "+e,"error")}o&&o.error?(n=!0,i=o.error):o&&o.invalid?(n=!0,i="Invalid policy document or request headers!"):o?c.expectingPolicy&&!o.policy?(n=!0,i="Response does not include the base64 encoded policy!"):o.signature||(n=!0,i="Response does not include the signature!"):(n=!0,i="Received an empty or invalid response from the server!"),n?(i&&c.log(i,"error"),a.failure(i)):u?d(u,o.signature,a):a.success(o)}function n(e,t,n){var i,o,r,s=new qq.Promise,a="POST",l=[],d="",h=new Date,f=function(e){var n,s=[];return qq.each(e.headers,function(e){l.push(e)}),l.sort(),qq.each(l,function(t,i){qq.indexOf(qq.s3.util.UNSIGNABLE_REST_HEADER_NAMES,i)<0?d+=i.toLowerCase()+":"+e.headers[i].trim()+"\n":"Content-MD5"===i?n=e.headers[i]:s.unshift(t)}),qq.each(s,function(e,t){l.splice(t,1)}),o={bucket:e.bucket,contentMd5:n,contentType:e.contentType,date:h,drift:c.signatureSpec.drift,endOfUrl:i,hashedContent:e.hashedContent,headerNames:l,headersStr:d,method:a},r=2===t?p.getStringToSign(o):q.getStringToSign(o),{date:h,endOfUrl:i,signedHeaders:4===t?q.getSignedHeaders(o.headerNames):null,toSign:4===t?r.hashed:r,toSignRaw:4===t?r.raw:r}};switch(n.type){case u.REQUEST_TYPE.MULTIPART_ABORT:a="DELETE",i=qq.format("uploadId={}",n.uploadId);break;case u.REQUEST_TYPE.MULTIPART_INITIATE:i="uploads";break;case u.REQUEST_TYPE.MULTIPART_COMPLETE:i=qq.format("uploadId={}",n.uploadId);break;case u.REQUEST_TYPE.MULTIPART_UPLOAD:a="PUT",i=qq.format("partNumber={}&uploadId={}",n.partNum,n.uploadId)}return i=n.key+"?"+i,4===t?q.getEncodedHashedPayload(n.content).then(function(e){n.headers["x-amz-content-sha256"]=e,n.headers.Host=n.host,n.headers["x-amz-date"]=qq.s3.util.getV4PolicyDate(h,c.signatureSpec.drift),n.hashedContent=e,s.success(f(n))},function(e){s.failure(e)}):s.success(f(n)),s}function i(e,t,n,i,s){var a;t.signatureConstructor?(s&&(a=t.signatureConstructor.getHeaders(),a[qq.s3.util.SESSION_TOKEN_PARAM_NAME]=s,t.signatureConstructor.withHeaders(a)),t.signatureConstructor.getToSign(e).then(function(e){r(t.signatureConstructor,e.stringToSign,n)},function(e){n.failure(e)})):(s&&qq.s3.util.refreshPolicyCredentials(t,s),o(t,n,i,s))}function o(e,t,n,i){4===c.signatureSpec.version?q.signPolicy(e,t,n,i):p.signPolicy(e,t,n,i)}function r(e,t,n){4===c.signatureSpec.version?q.signApiRequest(e,t,n):p.signApiRequest(e,t,n)}var s,a,u=this,l={},c={expectingPolicy:!1,method:"POST",signatureSpec:{drift:0,credentialsProvider:{},endpoint:null,customHeaders:{},version:2},maxConnections:3,endpointStore:{},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){}},d=function(e,t,n){var i=e.getHeaders();4===c.signatureSpec.version?i.Authorization=qq.s3.util.V4_ALGORITHM_PARAM_VALUE+" Credential="+c.signatureSpec.credentialsProvider.get().accessKey+"/"+qq.s3.util.getCredentialsDate(e.getRequestDate())+"/"+c.signatureSpec.region+"/s3/aws4_request,SignedHeaders="+e.getSignedHeaders()+",Signature="+t:i.Authorization="AWS "+c.signatureSpec.credentialsProvider.get().accessKey+":"+t,n.success(i,e.getEndOfUrl())},p={getStringToSign:function(e){return qq.format("{}\n{}\n{}\n\n{}/{}/{}",e.method,e.contentMd5||"",e.contentType||"",e.headersStr||"\n",e.bucket,e.endOfUrl)},signApiRequest:function(e,t,n){var i=qq.CryptoJS.enc.Utf8.parse(t),o=qq.CryptoJS.HmacSHA1(i,a.get().secretKey),r=qq.CryptoJS.enc.Base64.stringify(o);d(e,r,n)},signPolicy:function(e,t,n,i){var o=JSON.stringify(e),r=qq.CryptoJS.enc.Utf8.parse(o),s=qq.CryptoJS.enc.Base64.stringify(r),u=qq.CryptoJS.HmacSHA1(s,a.get().secretKey),l=qq.CryptoJS.enc.Base64.stringify(u);t.success({policy:s,signature:l},n,i)}},q={getCanonicalQueryString:function(e){var t,n,i,o=e.indexOf("?"),r="";return o>=0&&(t={},i=e.substr(o+1).split("&"),qq.each(i,function(e,n){var i=n.split("="),o=i[1];null==o&&(o=""),t[encodeURIComponent(i[0])]=encodeURIComponent(o)}),n=Object.keys(t).sort(),n.forEach(function(e,i){r+=e+"="+t[e],i0&&(t=e.substr(0,n)),"/"+t},getEncodedHashedPayload:function(e){var t,n=new qq.Promise;return qq.isBlob(e)?(t=new FileReader,t.onloadend=function(e){if(e.target.readyState===FileReader.DONE)if(e.target.error)n.failure(e.target.error);else{var t=qq.CryptoJS.lib.WordArray.create(e.target.result);n.success(qq.CryptoJS.SHA256(t).toString())}},t.readAsArrayBuffer(e)):(e=e||"",n.success(qq.CryptoJS.SHA256(e).toString())),n},getScope:function(e,t){return qq.s3.util.getCredentialsDate(e)+"/"+t+"/s3/aws4_request"},getStringToSign:function(e){var t=q.getCanonicalRequest(e),n=qq.s3.util.getV4PolicyDate(e.date,e.drift),i=qq.CryptoJS.SHA256(t).toString(),o=q.getScope(e.date,c.signatureSpec.region),r="AWS4-HMAC-SHA256\n{}\n{}\n{}";return{hashed:qq.format(r,n,o,i),raw:qq.format(r,n,o,t)}},getSignedHeaders:function(e){var t="";return e.forEach(function(n,i){t+=n.toLowerCase(),iDate.now()?i(e,t,u):a.onExpired().then(function(){i(e,t,u,a.get().accessKey,a.get().sessionToken)},function(e){c.log("Attempt to update expired credentials apparently failed! Unable to sign request. ","error"),u.failure("Unable to sign request - expired credentials.")}):(c.log("Submitting S3 signature request for "+e),r?r.getToSign(e).then(function(t){o={headers:t.stringToSignRaw},s.initTransport(e).withParams(o).withQueryParams(n).send()},function(e){c.log("Failed to construct signature. ","error"),u.failure("Failed to construct signature.")}):s.initTransport(e).withParams(o).withQueryParams(n).send(),l[e]={promise:u,signatureConstructor:r}),u},constructStringToSign:function(e,t,i,o){var r,s,u,l,d,p={};return{withHeaders:function(e){return p=e,this},withUploadId:function(e){return r=e,this},withContent:function(e){return s=e,this},withContentType:function(e){return u=e,this},withPartNum:function(e){return l=e,this},getToSign:function(q){var h=a.get().sessionToken,f=new qq.Promise,m=new Date(Date.now()+c.signatureSpec.drift);return p["x-amz-date"]=m.toUTCString(),h&&(p[qq.s3.util.SESSION_TOKEN_PARAM_NAME]=h),n(q,c.signatureSpec.version,{bucket:t,content:s,contentType:u,headers:p,host:i,key:o,partNum:l,type:e,uploadId:r}).then(function(e){d=e,f.success({headers:function(){return u&&(p["Content-Type"]=u),delete p.Host,p}(),date:d.date,endOfUrl:d.endOfUrl,signedHeaders:d.signedHeaders,stringToSign:d.toSign,stringToSignRaw:d.toSignRaw})},function(e){f.failure(e)}),f},getHeaders:function(){return qq.extend({},p)},getEndOfUrl:function(){return d&&d.endOfUrl},getRequestDate:function(){return d&&d.date},getSignedHeaders:function(){return d&&d.signedHeaders}}}})},qq.s3.RequestSigner.prototype.REQUEST_TYPE={MULTIPART_INITIATE:"multipart_initiate",MULTIPART_COMPLETE:"multipart_complete",MULTIPART_ABORT:"multipart_abort",MULTIPART_UPLOAD:"multipart_upload"},qq.UploadSuccessAjaxRequester=function(e){"use strict";function t(e,t,n){var r,s=i[e],a=t.responseText,u={success:!0},l={success:!1};delete i[e],o.log(qq.format("Received the following response body to an upload success request for id {}: {}",e,a));try{r=qq.parseJson(a),n||r&&(r.error||r.success===!1)?(o.log("Upload success request was rejected by the server.","error"),s.failure(qq.extend(r,l))):(o.log("Upload success was acknowledged by the server."),s.success(qq.extend(r,u)))}catch(t){n?(o.log(qq.format("Your server indicated failure in its upload success request response for id {}!",e),"error"),s.failure(l)):(o.log("Upload success was acknowledged by the server."),s.success(u))}}var n,i=[],o={method:"POST",endpoint:null,maxConnections:3,customHeaders:{},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){}};qq.extend(o,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",method:o.method,endpointStore:{get:function(){return o.endpoint}},paramsStore:o.paramsStore,maxConnections:o.maxConnections,customHeaders:o.customHeaders,log:o.log,onComplete:t,cors:o.cors})),qq.extend(this,{sendSuccessRequest:function(e,t){var r=new qq.Promise;return o.log("Submitting upload success request/notification for "+e),n.initTransport(e).withParams(t).send(),i[e]=r,r}})},qq.s3.InitiateMultipartAjaxRequester=function(e){"use strict";function t(e){var t,n=s.getBucket(e),i=s.getHost(e),r={},a=new qq.Promise,u=s.getKey(e);return r["x-amz-acl"]=s.aclStore.get(e),s.reducedRedundancy&&(r[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]=qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE),s.serverSideEncryption&&(r[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]=qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE),r[qq.s3.util.AWS_PARAM_PREFIX+s.filenameParam]=encodeURIComponent(s.getName(e)),qq.each(s.paramsStore.get(e),function(e,t){qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES,e)>=0?r[e]=t:r[qq.s3.util.AWS_PARAM_PREFIX+e]=encodeURIComponent(t)}),t=o.constructStringToSign(o.REQUEST_TYPE.MULTIPART_INITIATE,n,i,u).withContentType(s.getContentType(e)).withHeaders(r),o.getSignature(e,{signatureConstructor:t}).then(a.success,a.failure),a}function n(e,t,n){var i,o,a,u,l,c=r[e],d=new DOMParser,p=d.parseFromString(t.responseText,"application/xml");delete r[e],n?(l=t.status,o=p.getElementsByTagName("Message"),o.length>0&&(u=o[0].textContent)):(i=p.getElementsByTagName("UploadId"),i.length>0?a=i[0].textContent:u="Upload ID missing from request"),void 0===a?(u?s.log(qq.format("Specific problem detected initiating multipart upload request for {}: '{}'.",e,u),"error"):s.log(qq.format("Unexplained error with initiate multipart upload request for {}. Status code {}.",e,l),"error"),c.failure("Problem initiating upload request.",t)):(s.log(qq.format("Initiate multipart upload request successful for {}. Upload ID is {}",e,a)),c.success(a,t))}var i,o,r={},s={filenameParam:"qqfilename",method:"POST",endpointStore:null,paramsStore:null,signatureSpec:null,aclStore:null,reducedRedundancy:!1,serverSideEncryption:!1,maxConnections:3,getContentType:function(e){},getBucket:function(e){},getHost:function(e){},getKey:function(e){},getName:function(e){},log:function(e,t){}};qq.extend(s,e),o=new qq.s3.RequestSigner({endpointStore:s.endpointStore,signatureSpec:s.signatureSpec,cors:s.cors,log:s.log}),i=qq.extend(this,new qq.AjaxRequester({method:s.method,contentType:null,endpointStore:s.endpointStore,maxConnections:s.maxConnections,allowXRequestedWithAndCacheControl:!1,log:s.log,onComplete:n,successfulResponseCodes:{POST:[200]}})),qq.extend(this,{send:function(e){var n=new qq.Promise;return t(e).then(function(t,o){s.log("Submitting S3 initiate multipart upload request for "+e),r[e]=n,i.initTransport(e).withPath(o).withHeaders(t).send()},n.failure),n}})},qq.s3.CompleteMultipartAjaxRequester=function(e){"use strict";function t(e,t,n){var i=new qq.Promise,o=a.getBucket(e),s=a.getHost(e),u=r.constructStringToSign(r.REQUEST_TYPE.MULTIPART_COMPLETE,o,s,a.getKey(e)).withUploadId(t).withContent(n).withContentType("application/xml; charset=UTF-8");return r.getSignature(e,{signatureConstructor:u}).then(i.success,i.failure),i}function n(e,t,n){var i=s[e],o=new DOMParser,r=a.getBucket(e),u=(a.getKey(e),o.parseFromString(t.responseText,"application/xml")),l=u.getElementsByTagName("Bucket"),c=u.getElementsByTagName("Key");delete s[e],a.log(qq.format("Complete response status {}, body = {}",t.status,t.responseText)),n?a.log(qq.format("Complete Multipart Upload request for {} failed with status {}.",e,t.status),"error"):l.length&&c.length?l[0].textContent!==r&&(n=!0,a.log(qq.format("Wrong bucket in response to Complete Multipart Upload request for {}.",e),"error")):(n=!0,a.log(qq.format("Missing bucket and/or key in response to Complete Multipart Upload request for {}.",e),"error")),n?i.failure("Problem combining the file parts!",t):i.success({},t)}function i(e){var t=document.implementation.createDocument(null,"CompleteMultipartUpload",null);return e.sort(function(e,t){return e.part-t.part}),qq.each(e,function(e,n){var i=n.part,o=n.etag,r=t.createElement("Part"),s=t.createElement("PartNumber"),a=t.createTextNode(i),u=t.createTextNode(o),l=t.createElement("ETag");l.appendChild(u),s.appendChild(a),r.appendChild(s),r.appendChild(l),qq(t).children()[0].appendChild(r)}),(new XMLSerializer).serializeToString(t)}var o,r,s={},a={method:"POST",contentType:"text/xml",endpointStore:null,signatureSpec:null,maxConnections:3,getBucket:function(e){},getHost:function(e){},getKey:function(e){},log:function(e,t){}};qq.extend(a,e),r=new qq.s3.RequestSigner({endpointStore:a.endpointStore,signatureSpec:a.signatureSpec,cors:a.cors,log:a.log}),o=qq.extend(this,new qq.AjaxRequester({method:a.method,contentType:"application/xml; charset=UTF-8",endpointStore:a.endpointStore,maxConnections:a.maxConnections,allowXRequestedWithAndCacheControl:!1,log:a.log,onComplete:n,successfulResponseCodes:{POST:[200]}})),qq.extend(this,{send:function(e,n,r){var u=new qq.Promise,l=i(r);return t(e,n,l).then(function(t,n){a.log("Submitting S3 complete multipart upload request for "+e),s[e]=u,delete t["Content-Type"],o.initTransport(e).withPath(n).withHeaders(t).withPayload(l).send()},u.failure),u}})},qq.s3.AbortMultipartAjaxRequester=function(e){"use strict";function t(e,t){var n=new qq.Promise,i=r.getBucket(e),s=r.getHost(e),a=o.constructStringToSign(o.REQUEST_TYPE.MULTIPART_ABORT,i,s,r.getKey(e)).withUploadId(t);return o.getSignature(e,{signatureConstructor:a}).then(n.success,n.failure),n}function n(e,t,n){var i,o=new DOMParser,s=o.parseFromString(t.responseText,"application/xml"),a=s.getElementsByTagName("Error");r.log(qq.format("Abort response status {}, body = {}",t.status,t.responseText)),n?r.log(qq.format("Abort Multipart Upload request for {} failed with status {}.",e,t.status),"error"):a.length?(n=!0,i=s.getElementsByTagName("Message")[0].textContent,r.log(qq.format("Failed to Abort Multipart Upload request for {}. Error: {}",e,i),"error")):r.log(qq.format("Abort MPU request succeeded for file ID {}.",e))}var i,o,r={method:"DELETE",endpointStore:null,signatureSpec:null,maxConnections:3,getBucket:function(e){},getHost:function(e){},getKey:function(e){},log:function(e,t){}};qq.extend(r,e),o=new qq.s3.RequestSigner({endpointStore:r.endpointStore,signatureSpec:r.signatureSpec,cors:r.cors,log:r.log}),i=qq.extend(this,new qq.AjaxRequester({validMethods:["DELETE"],method:r.method,contentType:null,endpointStore:r.endpointStore,maxConnections:r.maxConnections,allowXRequestedWithAndCacheControl:!1,log:r.log,onComplete:n,successfulResponseCodes:{DELETE:[204]}})),qq.extend(this,{send:function(e,n){t(e,n).then(function(t,n){r.log("Submitting S3 Abort multipart upload request for "+e),i.initTransport(e).withPath(n).withHeaders(t).send()})}})},qq.s3.XhrUploadHandler=function(e,t){"use strict";var n=t.getName,i=t.log,o=e.clockDrift,r=200,s=e.getBucket,a=e.getHost,u=e.getKeyName,l=e.filenameParam,c=e.paramsStore,d=e.endpointStore,p=e.aclStore,q=e.objectProperties.reducedRedundancy,h=e.objectProperties.region,f=e.objectProperties.serverSideEncryption,m=e.validation,g=qq.extend({region:h,drift:o},e.signature),_=this,v=e.signature.credentialsProvider,b={combine:function(e){var t=_._getPersistableData(e).uploadId,n=_._getPersistableData(e).etags,i=new qq.Promise;return S.completeMultipart.send(e,t,n).then(i.success,function(t,n){i.failure(C.done(e,n).response,n)}),i},done:function(e,t,n){var i,o=C.response.parse(e,t);o.success&&(i=t.getResponseHeader("ETag"),_._getPersistableData(e).etags||(_._getPersistableData(e).etags=[]),_._getPersistableData(e).etags.push({part:n+1,etag:i}))},initHeaders:function(e,t,n){var i=C.bucket.getName(e),o=C.host.getName(e),r=C.key.urlSafe(e),s=new qq.Promise,a=S.restSignature.constructStringToSign(S.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD,i,o,r).withPartNum(t+1).withContent(n).withUploadId(_._getPersistableData(e).uploadId);return S.restSignature.getSignature(e+"."+t,{signatureConstructor:a}).then(s.success,s.failure),s},put:function(t,n){var o=_._createXhr(t,n),r=_._getChunkData(t,n),s=e.endpointStore.get(t),a=new qq.Promise;return b.initHeaders(t,n,r.blob).then(function(e,u){if(o._cancelled)i(qq.format("Upload of item {}.{} cancelled. Upload will not start after successful signature request.",t,n)),a.failure({error:"Chunk upload cancelled"});else{var l=s+"/"+u;_._registerProgressHandler(t,n,r.size),C.track(t,o,n).then(a.success,a.failure),o.open("PUT",l,!0),qq.each(e,function(e,t){o.setRequestHeader(e,t)}),o.send(r.blob)}},function(){a.failure({error:"Problem signing the chunk!"},o)}),a},send:function(e,t){var n=new qq.Promise;return b.setup(e).then(function(){b.put(e,t).then(n.success,n.failure)},function(e,t){n.failure({error:e},t)}),n},setup:function(e){var t=new qq.Promise,n=_._getPersistableData(e).uploadId,i=new qq.Promise;return n?n instanceof qq.Promise?n.then(function(e){t.success(e)}):t.success(n):(_._getPersistableData(e).uploadId=i,S.initiateMultipart.send(e).then(function(n){_._getPersistableData(e).uploadId=n,i.success(n),t.success(n)},function(n,o){_._getPersistableData(e).uploadId=null,t.failure(n,o),i.failure(n,o)})),t}},S={abortMultipart:new qq.s3.AbortMultipartAjaxRequester({endpointStore:d,signatureSpec:g,cors:e.cors,log:i,getBucket:function(e){return C.bucket.getName(e)},getHost:function(e){return C.host.getName(e)},getKey:function(e){return C.key.urlSafe(e)}}),completeMultipart:new qq.s3.CompleteMultipartAjaxRequester({endpointStore:d,signatureSpec:g,cors:e.cors,log:i,getBucket:function(e){return C.bucket.getName(e)},getHost:function(e){return C.host.getName(e)},getKey:function(e){return C.key.urlSafe(e)}}),initiateMultipart:new qq.s3.InitiateMultipartAjaxRequester({filenameParam:l,endpointStore:d,paramsStore:c,signatureSpec:g,aclStore:p,reducedRedundancy:q,serverSideEncryption:f,cors:e.cors,log:i,getContentType:function(e){return _._getMimeType(e)},getBucket:function(e){return C.bucket.getName(e)},getHost:function(e){return C.host.getName(e)},getKey:function(e){return C.key.urlSafe(e)},getName:function(e){return n(e)}}),policySignature:new qq.s3.RequestSigner({expectingPolicy:!0,signatureSpec:g,cors:e.cors,log:i}),restSignature:new qq.s3.RequestSigner({endpointStore:d,signatureSpec:g,cors:e.cors,log:i})},y={initParams:function(e){var t=c.get(e);return t[l]=n(e),qq.s3.util.generateAwsParams({endpoint:d.get(e),clockDrift:o,params:t,type:_._getMimeType(e),bucket:C.bucket.getName(e),key:_.getThirdPartyFileId(e),accessKey:v.get().accessKey,sessionToken:v.get().sessionToken,acl:p.get(e),expectedStatus:r,minFileSize:m.minSizeLimit,maxFileSize:m.maxSizeLimit,reducedRedundancy:q,region:h,serverSideEncryption:f,signatureVersion:g.version,log:i},qq.bind(S.policySignature.getSignature,this,e))},send:function(e){var t=new qq.Promise,n=_._createXhr(e),o=_.getFile(e);return _._registerProgressHandler(e),C.track(e,n).then(t.success,t.failure),y.setup(e,n,o).then(function(t){i("Sending upload request for "+e),n.send(t)},t.failure),t},setup:function(e,t,n){var i=new FormData,o=d.get(e),r=o,s=new qq.Promise;return y.initParams(e).then(function(e){t.open("POST",r,!0),qq.obj2FormData(e,i),i.append("file",n),s.success(i)},function(e){s.failure({error:e})}),s}},C={bucket:{promise:function(e){var t=new qq.Promise,n=_._getFileState(e).bucket;return n?t.success(n):s(e).then(function(n){_._getFileState(e).bucket=n,t.success(n)},t.failure),t},getName:function(e){return _._getFileState(e).bucket}},host:{promise:function(e){var t=new qq.Promise,n=_._getFileState(e).host;return n?t.success(n):a(e).then(function(n){_._getFileState(e).host=n,t.success(n)},t.failure),t},getName:function(e){return _._getFileState(e).host}},done:function(e,t){var n=C.response.parse(e,t),o=n.success!==!0;return o&&C.response.shouldReset(n.code)&&(i("This is an unrecoverable error, we must restart the upload entirely on the next retry attempt.","error"),n.reset=!0),{success:!o,response:n}},key:{promise:function(e){var t=new qq.Promise,i=_.getThirdPartyFileId(e);return null==i?(_._setThirdPartyFileId(e,t),u(e,n(e)).then(function(n){_._setThirdPartyFileId(e,n),t.success(n)},function(n){_._setThirdPartyFileId(e,null),t.failure(n)})):qq.isGenericPromise(i)?i.then(t.success,t.failure):t.success(i),t},urlSafe:function(e){var t=_.getThirdPartyFileId(e);return qq.s3.util.uriEscapePath(t)}},response:{parse:function(e,t){var n,o={};try{i(qq.format("Received response status {} with body: {}",t.status,t.responseText)),t.status===r?o.success=!0:(n=C.response.parseError(t.responseText),n&&(o.error=n.message,o.code=n.code))}catch(e){i("Error when attempting to parse xhr response text ("+e.message+")","error")}return o},parseError:function(e){var t,n,i=new DOMParser,o=i.parseFromString(e,"application/xml"),r=o.getElementsByTagName("Error"),s={};if(r.length)return t=o.getElementsByTagName("Code"),n=o.getElementsByTagName("Message"),n.length&&(s.message=n[0].textContent),t.length&&(s.code=t[0].textContent),s},shouldReset:function(e){return"EntityTooSmall"===e||"InvalidPart"===e||"InvalidPartOrder"===e||"NoSuchUpload"===e}},start:function(e,t){var n=new qq.Promise;return C.key.promise(e).then(function(){C.bucket.promise(e).then(function(){C.host.promise(e).then(function(){null==t?y.send(e).then(n.success,n.failure):b.send(e,t).then(n.success,n.failure)})})},function(e){n.failure({error:e})}),n},track:function(e,t,n){var i=new qq.Promise;return t.onreadystatechange=function(){if(4===t.readyState){var o;null==n?(o=C.done(e,t),i[o.success?"success":"failure"](o.response,t)):(b.done(e,t,n),o=C.done(e,t),i[o.success?"success":"failure"](o.response,t))}},i}};qq.extend(this,{uploadChunk:C.start,uploadFile:C.start}),qq.extend(this,new qq.XhrUploadHandler({options:qq.extend({namespace:"s3"},e),proxy:qq.extend({getEndpoint:e.endpointStore.get},t)})),qq.override(this,function(e){return{expunge:function(t){var n=_._getPersistableData(t)&&_._getPersistableData(t).uploadId,i=_._maybeDeletePersistedChunkData(t);void 0!==n&&i&&S.abortMultipart.send(t,n),e.expunge(t)},finalizeChunks:function(e){return b.combine(e)},_getLocalStorageId:function(t){var n=e._getLocalStorageId(t),i=C.bucket.getName(t);return n+"-"+i}}})},qq.s3.FormUploadHandler=function(e,t){"use strict";function n(t,n){var i,o,r,s=(e.endpointStore.get(t),a._getFileState(t).bucket);try{if(i=n.contentDocument||n.contentWindow.document,o=i.body.innerHTML,r=qq.s3.util.parseIframeResponse(n),r.bucket===s&&r.key===qq.s3.util.encodeQueryStringParam(a.getThirdPartyFileId(t)))return!0;p("Response from AWS included an unexpected bucket or key name.","error")}catch(e){p("Error when attempting to parse form upload response ("+e.message+")","error")}return!1}function i(e){var t=m.get(e);return t[f]=c(e),qq.s3.util.generateAwsParams({endpoint:g.get(e),clockDrift:u,params:t,bucket:a._getFileState(e).bucket,key:a.getThirdPartyFileId(e),accessKey:x.get().accessKey,sessionToken:x.get().sessionToken,acl:_.get(e),minFileSize:y.minSizeLimit,maxFileSize:y.maxSizeLimit,successRedirectUrl:w,reducedRedundancy:v,region:b,serverSideEncryption:S,signatureVersion:C.version,log:p},qq.bind(E.getSignature,this,e))}function o(t,n){var o=new qq.Promise,r="POST",u=e.endpointStore.get(t),l=c(t);return i(t).then(function(e){var t=a._initFormForUpload({method:r,endpoint:u,params:e,paramsInBody:!0,targetName:n.name});o.success(t)},function(e){o.failure(e),s(t,n,l,{error:e})}),o}function r(e){var t=a._createIframe(e),i=a.getInput(e),r=new qq.Promise;return o(e,t).then(function(o){o.appendChild(i),a._attachLoadEvent(t,function(i){p("iframe loaded"),i?i.success===!1&&(p("Amazon likely rejected the upload request","error"),r.failure(i)):(i={},i.success=n(e,t),i.success===!1?(p("A success response was received by Amazon, but it was invalid in some way.","error"),r.failure(i)):(qq.extend(i,qq.s3.util.parseIframeResponse(t)),r.success(i))),s(e,t)}),p("Sending upload request for "+e),o.submit(),qq(o).remove()},r.failure),r}function s(e,t){a._detachLoadEvent(e),t&&qq(t).remove()}var a=this,u=e.clockDrift,l=t.onUuidChanged,c=t.getName,d=t.getUuid,p=t.log,q=e.getBucket,h=e.getKeyName,f=e.filenameParam,m=e.paramsStore,g=e.endpointStore,_=e.aclStore,v=e.objectProperties.reducedRedundancy,b=e.objectProperties.region,S=e.objectProperties.serverSideEncryption,y=e.validation,C=e.signature,w=e.iframeSupport.localBlankPagePath,x=e.signature.credentialsProvider,E=new qq.s3.RequestSigner({signatureSpec:C,cors:e.cors,log:p});if(void 0===w)throw new Error("successRedirectEndpoint MUST be defined if you intend to use browsers that do not support the File API!");qq.extend(this,new qq.FormUploadHandler({options:{isCors:!1,inputName:"file"},proxy:{onCancel:e.onCancel,onUuidChanged:l,getName:c,getUuid:d,log:p}})),qq.extend(this,{uploadFile:function(e){var t=c(e),n=new qq.Promise;return a.getThirdPartyFileId(e)?a._getFileState(e).bucket?r(e).then(n.success,n.failure):q(e).then(function(t){a._getFileState(e).bucket=t,r(e).then(n.success,n.failure)}):h(e,t).then(function(t){q(e).then(function(i){a._getFileState(e).bucket=i,a._setThirdPartyFileId(e,t),r(e).then(n.success,n.failure)},function(e){n.failure({error:e})})},function(e){n.failure({error:e})}),n}})},function(){"use strict";qq.s3.FineUploader=function(e){var t={failedUploadTextDisplay:{mode:"custom"}};qq.extend(t,e,!0),qq.FineUploader.call(this,t,"s3"),qq.supportedFeatures.ajaxUploading||void 0!==t.iframeSupport.localBlankPagePath||(this._options.element.innerHTML="You MUST set the localBlankPagePath
property of the iframeSupport
option since this browser does not support the File API!
")},qq.extend(qq.s3.FineUploader.prototype,qq.s3.FineUploaderBasic.prototype),qq.extend(qq.s3.FineUploader.prototype,qq.uiPublicApi),qq.extend(qq.s3.FineUploader.prototype,qq.uiPrivateApi)}(),qq.azure=qq.azure||{},qq.azure.util=qq.azure.util||function(){"use strict";return{AZURE_PARAM_PREFIX:"x-ms-meta-",_paramNameMatchesAzureParameter:function(e){switch(e){case"Cache-Control":case"Content-Disposition":case"Content-Encoding":case"Content-MD5":case"x-ms-blob-content-encoding":case"x-ms-blob-content-disposition":case"x-ms-blob-content-md5":case"x-ms-blob-cache-control":return!0;default:return!1}},_getPrefixedParamName:function(e){return qq.azure.util._paramNameMatchesAzureParameter(e)?e:qq.azure.util.AZURE_PARAM_PREFIX+e},getParamsAsHeaders:function(e){var t={};return qq.each(e,function(e,n){var i=qq.azure.util._getPrefixedParamName(e),o=null;qq.isFunction(n)?o=String(n()):qq.isObject(n)?qq.extend(t,qq.azure.util.getParamsAsHeaders(n)):o=String(n),null!==o&&(qq.azure.util._paramNameMatchesAzureParameter(e)?t[i]=o:t[i]=encodeURIComponent(o))}),t},parseAzureError:function(e,t){var n,i,o=new DOMParser,r=o.parseFromString(e,"application/xml"),s=r.getElementsByTagName("Error")[0],a={};if(t("Received error response: "+e,"error"),s)return i=s.getElementsByTagName("Message")[0],i&&(a.message=i.textContent),n=s.getElementsByTagName("Code")[0],n&&(a.code=n.textContent),t("Parsed Azure error: "+JSON.stringify(a),"error"),a}}}(),function(){"use strict";qq.nonTraditionalBasePublicApi={setUploadSuccessParams:function(e,t){this._uploadSuccessParamsStore.set(e,t)},setUploadSuccessEndpoint:function(e,t){this._uploadSuccessEndpointStore.set(e,t)}},qq.nonTraditionalBasePrivateApi={_onComplete:function(e,t,n,i){var o,r,s=!!n.success,a=this,u=arguments,l=this._uploadSuccessEndpointStore.get(e),c=this._options.uploadSuccess.customHeaders,d=this._options.uploadSuccess.method,p=this._options.cors,q=new qq.Promise,h=this._uploadSuccessParamsStore.get(e),f=this._paramsStore.get(e),m=function(t){delete a._failedSuccessRequestCallbacks[e],qq.extend(n,t),qq.FineUploaderBasic.prototype._onComplete.apply(a,u),q.success(t)},g=function(r){var s=o;qq.extend(n,r),n&&n.reset&&(s=null),s?a._failedSuccessRequestCallbacks[e]=s:delete a._failedSuccessRequestCallbacks[e],a._onAutoRetry(e,t,n,i,s)||(qq.FineUploaderBasic.prototype._onComplete.apply(a,u),q.failure(r))};return s&&l?(r=new qq.UploadSuccessAjaxRequester({endpoint:l,method:d,customHeaders:c,cors:p,log:qq.bind(this.log,this)}),qq.extend(h,a._getEndpointSpecificParams(e,n,i),!0),f&&qq.extend(h,f,!0),o=qq.bind(function(){r.sendSuccessRequest(e,h).then(m,g)},a),o(),q):qq.FineUploaderBasic.prototype._onComplete.apply(this,arguments)},_manualRetry:function(e){var t=this._failedSuccessRequestCallbacks[e];return qq.FineUploaderBasic.prototype._manualRetry.call(this,e,t)}}}(),function(){"use strict";qq.azure.FineUploaderBasic=function(e){if(!qq.supportedFeatures.ajaxUploading)throw new qq.Error("Uploading directly to Azure is not possible in this browser.");var t={signature:{endpoint:null,customHeaders:{}},blobProperties:{name:"uuid"},uploadSuccess:{endpoint:null,method:"POST",params:{},customHeaders:{}},chunking:{partSize:4e6,minFileSize:4000001}};qq.extend(t,e,!0),qq.FineUploaderBasic.call(this,t),this._uploadSuccessParamsStore=this._createStore(this._options.uploadSuccess.params),this._uploadSuccessEndpointStore=this._createStore(this._options.uploadSuccess.endpoint),
+this._failedSuccessRequestCallbacks={},this._cannedBlobNames={}},qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,{getBlobName:function(e){return null==this._cannedBlobNames[e]?this._handler.getThirdPartyFileId(e):this._cannedBlobNames[e]},_getEndpointSpecificParams:function(e){return{blob:this.getBlobName(e),uuid:this.getUuid(e),name:this.getName(e),container:this._endpointStore.get(e)}},_createUploadHandler:function(){return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,{signature:this._options.signature,onGetBlobName:qq.bind(this._determineBlobName,this),deleteBlob:qq.bind(this._deleteBlob,this,!0)},"azure")},_determineBlobName:function(e){var t=this._options.blobProperties.name,n=this.getUuid(e),i=this.getName(e),o=qq.getExtension(i),r=n;if(!qq.isString(t))return t.call(this,e);switch(t){case"uuid":return void 0!==o&&(r+="."+o),(new qq.Promise).success(r);case"filename":return(new qq.Promise).success(i);default:return new qq.Promise.failure("Invalid blobName option value - "+t)}},_addCannedFile:function(e){var t;if(null==e.blobName)throw new qq.Error("Did not find blob name property in server session response. This is required!");return t=qq.FineUploaderBasic.prototype._addCannedFile.apply(this,arguments),this._cannedBlobNames[t]=e.blobName,t},_deleteBlob:function(e,t){var n=this,i={},o={get:function(e){return n._endpointStore.get(e)+"/"+n.getBlobName(e)}},r={get:function(e){return i[e]}},s=function(e,t){i[e]=t,u.send(e)},a=function(t,i,o){e?(n.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS","error"),qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t))):(n._onDeleteComplete(t,o,!0),n._options.callbacks.onDeleteComplete(t,o,!0))},u=new qq.azure.DeleteBlob({endpointStore:r,log:qq.bind(n.log,n),onDelete:function(e){n._onDelete(e),n._options.callbacks.onDelete(e)},onDeleteComplete:function(t,o,r){delete i[t],r&&(e?n.log("Will cancel upload, but failed to remove uncommitted parts from Azure.","error"):qq.azure.util.parseAzureError(o.responseText,qq.bind(n.log,n))),e?(qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t)),n.log("Deleted uncommitted blob chunks for "+t)):(n._onDeleteComplete(t,o,r),n._options.callbacks.onDeleteComplete(t,o,r))}}),l=new qq.azure.GetSas({cors:this._options.cors,customHeaders:this._options.signature.customHeaders,endpointStore:{get:function(){return n._options.signature.endpoint}},restRequestVerb:u.method,log:qq.bind(n.log,n)});l.request(t,o.get(t)).then(qq.bind(s,n,t),qq.bind(a,n,t))},_createDeleteHandler:function(){var e=this;return{sendDelete:function(t,n){e._deleteBlob(!1,t)}}}})}(),qq.azure.XhrUploadHandler=function(e,t){"use strict";function n(e){var t=new qq.Promise;return o(e).then(function(n){var i=s._getMimeType(e),o=s._getPersistableData(e).blockIdEntries;v.putBlockList.send(e,n,o,i,function(t){s._registerXhr(e,null,t,v.putBlockList)}).then(function(n){a("Success combining chunks for id "+e),t.success({},n)},function(n){a("Attempt to combine chunks failed for id "+e,"error"),r(n,t)})},t.failure),t}function i(e){var t=l.get(e),n=new qq.Promise,i=function(i){s._setThirdPartyFileId(e,i),n.success(t+"/"+i)},o=function(e){n.failure(e)};return f(e).then(i,o),n}function o(e,t){var n=null==t?e:e+"."+t,o=new qq.Promise,r=function(e){a("GET SAS request succeeded."),o.success(e)},s=function(e,t){a("GET SAS request failed: "+e,"error"),o.failure({error:"Problem communicating with local server"},t)},u=function(e){v.getSasForPutBlobOrBlock.request(n,e).then(r,s)},l=function(t){a(qq.format("Failed to determine blob name for ID {} - {}",e,t),"error"),o.failure({error:t})};return i(e).then(u,l),o}function r(e,t){var n=qq.azure.util.parseAzureError(e.responseText,a),i="Problem sending file to Azure";t.failure({error:i,azureError:n&&n.message,reset:403===e.status})}var s=this,a=t.log,u=e.cors,l=e.endpointStore,c=e.paramsStore,d=e.signature,p=e.filenameParam,q=e.chunking.minFileSize,h=e.deleteBlob,f=e.onGetBlobName,m=t.getName,g=t.getSize,_=function(e){var t=c.get(e);return t[p]=m(e),t},v={putBlob:new qq.azure.PutBlob({getBlobMetadata:_,log:a}),putBlock:new qq.azure.PutBlock({log:a}),putBlockList:new qq.azure.PutBlockList({getBlobMetadata:_,log:a}),getSasForPutBlobOrBlock:new qq.azure.GetSas({cors:u,customHeaders:d.customHeaders,endpointStore:{get:function(){return d.endpoint}},log:a,restRequestVerb:"PUT"})};qq.extend(this,{uploadChunk:function(e,t){var n=new qq.Promise;return o(e,t).then(function(i){var o=s._createXhr(e,t),u=s._getChunkData(e,t);s._registerProgressHandler(e,t,u.size),s._registerXhr(e,t,o,v.putBlock),v.putBlock.upload(e+"."+t,o,i,t,u.blob).then(function(t){s._getPersistableData(e).blockIdEntries||(s._getPersistableData(e).blockIdEntries=[]),s._getPersistableData(e).blockIdEntries.push(t),a("Put Block call succeeded for "+e),n.success({},o)},function(){a(qq.format("Put Block call failed for ID {} on part {}",e,t),"error"),r(o,n)})},n.failure),n},uploadFile:function(e){var t=new qq.Promise,n=s.getFile(e);return o(e).then(function(i){var o=s._createXhr(e);s._registerProgressHandler(e),v.putBlob.upload(e,o,i,n).then(function(){a("Put Blob call succeeded for "+e),t.success({},o)},function(){a("Put Blob call failed for "+e,"error"),r(o,t)})},t.failure),t}}),qq.extend(this,new qq.XhrUploadHandler({options:qq.extend({namespace:"azure"},e),proxy:qq.extend({getEndpoint:e.endpointStore.get},t)})),qq.override(this,function(e){return{expunge:function(t){var n=s._wasCanceled(t),i=s._getPersistableData(t),o=i&&i.blockIdEntries||[];n&&o.length>0&&h(t),e.expunge(t)},finalizeChunks:function(e){return n(e)},_shouldChunkThisFile:function(t){var n=e._shouldChunkThisFile(t);return n&&g(t)>=q}}})},qq.azure.GetSas=function(e){"use strict";function t(e,t,n){var i=o[e];n?i.failure("Received response code "+t.status,t):t.responseText.length?i.success(t.responseText):i.failure("Empty response.",t),delete o[e]}var n,i={cors:{expected:!1,sendCredentials:!1},customHeaders:{},restRequestVerb:"PUT",endpointStore:null,log:function(e,t){}},o={};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",successfulResponseCodes:{GET:[200]},contentType:null,customHeaders:i.customHeaders,endpointStore:i.endpointStore,cors:i.cors,log:i.log,onComplete:t})),qq.extend(this,{request:function(e,t){var r=new qq.Promise,s=i.restRequestVerb;return i.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.",s,e)),o[e]=r,n.initTransport(e).withParams({bloburi:t,_method:s}).withCacheBuster().send(),r}})},qq.UploadSuccessAjaxRequester=function(e){"use strict";function t(e,t,n){var r,s=i[e],a=t.responseText,u={success:!0},l={success:!1};delete i[e],o.log(qq.format("Received the following response body to an upload success request for id {}: {}",e,a));try{r=qq.parseJson(a),n||r&&(r.error||r.success===!1)?(o.log("Upload success request was rejected by the server.","error"),s.failure(qq.extend(r,l))):(o.log("Upload success was acknowledged by the server."),s.success(qq.extend(r,u)))}catch(t){n?(o.log(qq.format("Your server indicated failure in its upload success request response for id {}!",e),"error"),s.failure(l)):(o.log("Upload success was acknowledged by the server."),s.success(u))}}var n,i=[],o={method:"POST",endpoint:null,maxConnections:3,customHeaders:{},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){}};qq.extend(o,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",method:o.method,endpointStore:{get:function(){return o.endpoint}},paramsStore:o.paramsStore,maxConnections:o.maxConnections,customHeaders:o.customHeaders,log:o.log,onComplete:t,cors:o.cors})),qq.extend(this,{sendSuccessRequest:function(e,t){var r=new qq.Promise;return o.log("Submitting upload success request/notification for "+e),n.initTransport(e).withParams(t).send(),i[e]=r,r}})},qq.azure.DeleteBlob=function(e){"use strict";var t,n="DELETE",i={endpointStore:{},onDelete:function(e){},onDeleteComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[202],e}(),contentType:null,endpointStore:i.endpointStore,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete})),qq.extend(this,{method:n,send:function(e){return i.log("Submitting Delete Blob request for "+e),t.initTransport(e).send()}})},qq.azure.PutBlob=function(e){"use strict";var t,n="PUT",i={getBlobMetadata:function(e){},log:function(e,t){}},o={},r={},s={get:function(e){return o[e]}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[201],e}(),contentType:null,customHeaders:function(e){var t=i.getBlobMetadata(e),n=qq.azure.util.getParamsAsHeaders(t);return n["x-ms-blob-type"]="BlockBlob",n},endpointStore:s,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onComplete:function(e,t,n){var i=r[e];delete o[e],delete r[e],n?i.failure():i.success()}})),qq.extend(this,{method:n,upload:function(e,n,s,a){var u=new qq.Promise;return i.log("Submitting Put Blob request for "+e),r[e]=u,o[e]=s,t.initTransport(e).withPayload(a).withHeaders({"Content-Type":a.type}).send(n),u}})},qq.azure.PutBlock=function(e){"use strict";function t(e){var t=5,n=new Array(t+1).join("0"),i=(n+e).slice(-t);return btoa(i)}var n,i="PUT",o={},r={},s={log:function(e,t){}},a={},u={get:function(e){return a[e]}};qq.extend(s,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),contentType:null,endpointStore:u,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:s.log,onComplete:function(e,t,n){var i=r[e],s=o[e];delete a[e],delete r[e],delete o[e],n?i.failure():i.success(s)}})),qq.extend(this,{method:i,upload:function(e,i,u,l,c){var d=new qq.Promise,p=t(l);return r[e]=d,s.log(qq.format("Submitting Put Block request for {} = part {}",e,l)),a[e]=qq.format("{}&comp=block&blockid={}",u,encodeURIComponent(p)),o[e]={part:l,id:p},n.initTransport(e).withPayload(c).send(i),d}})},qq.azure.PutBlockList=function(e){"use strict";function t(e){var t=document.implementation.createDocument(null,"BlockList",null);return e.sort(function(e,t){return e.part-t.part}),qq.each(e,function(e,n){var i=t.createElement("Latest"),o=t.createTextNode(n.id);i.appendChild(o),qq(t).children()[0].appendChild(i)}),(new XMLSerializer).serializeToString(t)}var n,i="PUT",o={},r={getBlobMetadata:function(e){},log:function(e,t){}},s={},a={get:function(e){return s[e]}};qq.extend(r,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),customHeaders:function(e){var t=r.getBlobMetadata(e);return qq.azure.util.getParamsAsHeaders(t)},contentType:"text/plain",endpointStore:a,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:r.log,onSend:function(){},onComplete:function(e,t,n){var i=o[e];delete s[e],delete o[e],n?i.failure(t):i.success(t)}})),qq.extend(this,{method:i,send:function(e,i,a,u,l){var c,d=new qq.Promise,p=t(a);return o[e]=d,r.log(qq.format("Submitting Put Block List request for {}",e)),s[e]=qq.format("{}&comp=blocklist",i),c=n.initTransport(e).withPayload(p).withHeaders({"x-ms-blob-content-type":u}).send(),l(c),d}})},function(){"use strict";qq.azure.FineUploader=function(e){var t={failedUploadTextDisplay:{mode:"custom"}};qq.extend(t,e,!0),qq.FineUploader.call(this,t,"azure")},qq.extend(qq.azure.FineUploader.prototype,qq.azure.FineUploaderBasic.prototype),qq.extend(qq.azure.FineUploader.prototype,qq.uiPublicApi),qq.extend(qq.azure.FineUploader.prototype,qq.uiPrivateApi),qq.extend(qq.azure.FineUploader.prototype,{})}()}(window);
+//# sourceMappingURL=all.fine-uploader.min.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.min.js.map b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.min.js.map
new file mode 100644
index 000000000000..9d67150c1fba
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/all.fine-uploader.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/traditional/traditional.form.upload.handler.js","../client/js/traditional/traditional.xhr.upload.handler.js","../client/js/traditional/all-chunks-done.ajax.requester.js","../client/js/dnd.js","../client/js/uploader.api.js","../client/js/uploader.js","../client/js/templating.js","../client/js/ui.handler.events.js","../client/js/ui.handler.click.filebuttons.js","../client/js/ui.handler.click.filename.js","../client/js/ui.handler.focusin.filenameinput.js","../client/js/ui.handler.focus.filenameinput.js","../client/js/ui.handler.edit.filename.js","../client/js/third-party/crypto-js/core.js","../client/js/third-party/crypto-js/enc-base64.js","../client/js/third-party/crypto-js/hmac.js","../client/js/third-party/crypto-js/sha1.js","../client/js/third-party/crypto-js/sha256.js","../client/js/third-party/crypto-js/lib-typedarrays.js","../client/js/s3/util.js","../client/js/non-traditional-common/uploader.basic.api.js","../client/js/s3/uploader.basic.js","../client/js/s3/request-signer.js","../client/js/uploadsuccess.ajax.requester.js","../client/js/s3/multipart.initiate.ajax.requester.js","../client/js/s3/multipart.complete.ajax.requester.js","../client/js/s3/multipart.abort.ajax.requester.js","../client/js/s3/s3.xhr.upload.handler.js","../client/js/s3/s3.form.upload.handler.js","../client/js/s3/uploader.js","../client/js/azure/util.js","../client/js/azure/uploader.basic.js","../client/js/azure/azure.xhr.upload.handler.js","../client/js/azure/get-sas.js","../client/js/azure/rest/delete-blob.js","../client/js/azure/rest/put-blob.js","../client/js/azure/rest/put-block.js","../client/js/azure/rest/put-block-list.js","../client/js/azure/uploader.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","intArray","mimeString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","testSupportsFileInputElement","tempInput","supported","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","createInput","BUTTON_ID_ATTR_NAME","buttonId","options","title","self","setMultiple","folders","acceptFiles","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","disposeSupport","onChange","hoverClass","focusClass","ios8BrowserCrashWorkaround","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","byUuid","getDataByStatus","status","statusResults","statuses","index","statusEnum","statusResultIndexes","byStatus","dataIndex","byProxyGroupId","byBatchId","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","params","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","_options","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","fileOrUrl","promiseToReturn","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","callbacks","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","toUpperCase","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","allowedExtensions","accept","validation","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","namespace","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","replacement","extensionsForMessage","placeholderMatch","messages","names","validationBase","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","requestData","dequeue","nextId","queue","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","mandatedParams","optXhr","url","payload","onSend","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","shouldParamsBeInQueryString","contentType","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","acceptHeader","setRequestHeader","allowXRequestedWithAndCacheControl","responseCode","successfulResponseCodes","prepareToSend","validMethods","DELETE","PATCH","POST","PUT","GET","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","preventRetryResponse","controller","chunkingPossible","concurrentChunkingPossible","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","inProgressIdx","responseToReport","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","expungeFile","detachLoadEvents","isCors","postMessageCallbackTimers","corsMessageReceiver","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","onloadCallbacks","onloadCallback","_parseJsonResponse","_detachLoadEvent","formHandlerInstanceId","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","xhrId","ajaxRequester","_getAjaxRequester","chunkFiles","resumeEnabled","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","getMandatedParams","_method","requester","detectSubsampling","img","ctx","iw","naturalWidth","ih","naturalHeight","width","getContext","drawImage","getImageData","detectVerticalSquash","alpha","ratio","sy","ey","py","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","tmpCtx","sx","dx","d","tmpCanvas","vertSquashRatio","dw","dh","dy","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","opt","imgWidth","imgHeight","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","el","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetProtocol","targetHostname","targetPort","targetAnchor","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","TAG_IDS","vals","tagValHex","tagValLength","idHex","tagsToFindIdx","TAG_INFO","274","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","chr1","chr2","enc1","enc2","enc3","output","chr3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","isImage","registerPasteHandler","detachPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","determineNewEndpoint","formEl","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","_form2Obj","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","getIframeContentJson","doc","innerHtml","contentWindow","nodeValue","createForm","responseFromMessage","multipart","addChunkingSpecificParams","allChunksDoneRequester","AllChunksDoneAjaxRequester","createReadyStateChangedHandler","onUploadOrChunkComplete","getChunksCompleteParams","isErrorUploadResponse","parseResponse","sendChunksCompleteRequest","complete","setParamsAndGetEntityToSend","setUploadHeaders","extraHeaders","toSend","promises","endpointHandler","DragAndDrop","uploadDroppedFiles","uploadDropZone","filesAsArray","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","parseEntryPromise","fullPath","indexOfNameInFullPath","qqPath","droppedFiles","fileError","isDirectory","getFilesInDirectory","entriesLeft","accumEntries","existingPromise","dirReader","createReader","readEntries","newEntries","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","allowMultipleItems","dropError","setupDropzone","dropArea","dropZone","UploadDropZone","HIDE_ZONES_EVENT_NAME","onEnter","dropActive","stopPropagation","onLeaveNotDescendants","onDrop","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","relatedTarget","y","setupDragDrop","dropZones","dropZoneElements","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","targetEl","errorSpecifics","dragoverShouldBeCanceled","disableDropOutside","dropOutsideDisabled","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","isOrSetDropDisabled","isDisabled","preventDrop","triggerHidezonesEvent","triggerUsingOldApi","hideZonesEvent","createEvent","initEvent","CustomEvent","dispatchEvent","attachEvents","effect","elementFromPoint","clientX","clientY","uiPublicApi","_parent","_templating","addCacheToDom","clearFiles","addExtraDropzone","_dnd","removeExtraDropzone","getItemByFileId","isHiddenForever","getFileContainer","_setupDragAndDrop","_totalFilesInBatch","_filesInBatchAddedToUi","_setupClickAndEditEventHandlers","formattedFilename","updateFilename","uploadPaused","continued","uploadContinued","getId","fileContainerOrChildEl","getFileId","getDropTarget","qqDropTarget","uiPrivateApi","_removeFileItem","removeFile","_fileButtonsClickHandler","FileButtonsClickHandler","_bindFileButtonsClickEvent","_focusinEventSupported","_isEditFilenameEnabled","_filenameClickHandler","_bindFilenameClickEvent","_filenameInputFocusInHandler","_bindFilenameInputFocusInEvent","_filenameInputFocusHandler","_bindFilenameInputFocusEvent","dragAndDrop","extraDropzones","templating","defaultDropZone","getDropZone","showDropProcessing","hideDropProcessing","errorData","lvl","onDeleteFile","onRetry","onPause","onContinue","onGetName","isEditFilenamePossible","FilenameClickHandler","FilenameInputFocusHandler","_filenameEditHandler","onGetUploadStatus","onSetName","onEditingStatusChange","isEditing","qqInput","getEditInput","qqFileContainer","hideFilename","hideEditIcon","showFilename","showEditIcon","markFilenameEditable","hideRetry","setStatusText","_classes","retrying","hidePause","FilenameInputFocusInHandler","hideSpinner","resetTotalProgress","reportDirectoryPaths","qqpath","_addToList","addHandler","updateProgress","hideCancel","hideProgress","waitingForResponse","_displayFileSize","completeUpload","_markFileAsSuccessful","fail","showCancel","isRetryPossible","showRetry","_controlFailureTextDisplay","parentRetVal","newResult","showDeleteButton","_maybeUpdateThumbnail","showSpinner","allowPause","retryNumForDisplay","maxAuto","retryNote","_showCancelLink","showAutoRetryNote","autoRetryNote","resetProgress","_onSubmitDeleteSuccess","forceConfirm","_showDeleteConfirm","_sendDeleteRequest","deletingFailedText","hideDeleteButton","deletingStatusText","confirmMessage","deleteRequestArgs","showConfirm","canned","prependData","prependIndex","dontDisplay","hideScaled","prependFiles","disableCancel","_handledProxyGroup","_clearList","addFileToCache","updateThumbnail","thumbnails","generatePreview","fileSizeOnSubmit","loadedSize","sizeForDisplay","_formatProgress","uploadedSize","formatProgress","mode","responseProperty","failureReason","failedUploadTextDisplay","failUpload","enableTooltip","_showTooltip","showMessage","_setupPastePrompt","namePromptMessage","defaultVal","showPrompt","fileStatus","placeholders","waitUntilResponse","FineUploader","listElement","template","editable","tooManyFilesError","unsupportedBrowser","promptForName","maxCount","notAvailablePath","waitingPath","timeBetweenThumbs","hasDialog","showDialog","confirm","defaultValue","prompt","Templating","templateIdOrEl","containerEl","fileContainerEl","maxThumbs","waitUntilUpdate","thumbnailNotAvailable","waitingForThumbnail","renderFailure","isEditElementsExist","isRetryElementExist","templateHtml","showThumbnails","serverScale","FILE_ID_ATTR","FILE_CLASS_PREFIX","THUMBNAIL_MAX_SIZE_ATTR","THUMBNAIL_SERVER_SCALE_ATTR","HIDE_DROPZONE_ATTR","DROPZPONE_TEXT_ATTR","IN_PROGRESS_CLASS","HIDDEN_FOREVER_CLASS","fileBatch","content","createDocumentFragment","map","isCancelDisabled","generatedThumbnails","thumbnailQueueMonitorRunning","thumbGenerationQueue","thumbnailMaxSize","selectorClasses","alertDialog","dialogCancelButton","confirmDialog","dialogMessage","dialogOkButton","promptDialog","uploader","drop","list","progressBarContainer","totalProgressBarContainer","totalProgressBar","spinner","continueButton","deleteButton","statusText","editFilenameInput","editNameIcon","dropText","dropProcessing","dropProcessingSpinner","thumbnail","previewGeneration","cachedThumbnailNotAvailableImg","cachedWaitingForThumbnailImg","cacheThumbnailPlaceholders","notAvailableUrl","waitingUrl","updatedImg","displayWaitingImg","waitingImgPlacement","maybeScalePlaceholderViaCss","show","generateNewPreview","getThumbnail","qqThumbnailId","maybeSetDisplayNotAvailableImg","generateNextQueuedPreview","queuedThumbRequest","update","processUpdateQueuedPreviewRequest","processNewQueuedPreviewRequest","getCancel","getTemplateEl","getContinue","getDialog","getDelete","getDropProcessing","getEditIcon","getPause","getProgress","getRetry","getSpinner","cssClass","previewing","notAvailableImgPlacement","parseAndGetTemplate","scriptEl","scriptHtml","fileListNode","tempTemplateEl","fileListHtml","defaultButton","dropTextEl","uploaderEl","fileTemplate","prependFile","parentEl","beforeEl","optFileOrBlob","relatedThumbnailId","useCachedPreview","showWaitingImg","setProgressBarWidth","percent","bar","progressBarSelector","targetThumbnailId","cachedThumbnailId","targetThumbnail","cachedThumbnail","hideTotalProgress","cantRenderEl","prependInfo","hideForever","batch","thumb","fileEl","fileNameEl","waitingImg","currentNode","getFileList","filenameEl","isFileName","icon","isEditIcon","isEditInput","isCancel","allowContinueButton","isPause","isContinueButton","isDeleteButton","isRetry","textEl","dialog","messageEl","inputEl","cancelBtn","okBtn","closeHandler","cancelClickHandler","okClickHandler","close","showModal","UiEventHandler","s","protectedApi","eventType","srcElement","onHandled","attachTo","getFileIdFromItem","qqFileId","getDisposeSupport","examineEvent","buttonHandlers","buttonType","firstLetterCapButtonType","inheritedInternalApi","handleFilenameEdit","FilenameEditHandler","handleInputFocus","getFilenameSansExtension","filenameSansExt","getOriginalExtension","origName","handleNameUpdate","newFilenameInputEl","origExtension","registerInputBlurHandler","registerInputEnterKeyHandler","keyCode","which","focusInput","focus","CryptoJS","C","C_lib","lib","Base","F","overrides","subtype","mixIn","init","$super","instance","properties","propertyName","clone","WordArray","words","sigBytes","encoder","Hex","wordArray","thisWords","thatWords","thisSigBytes","thatSigBytes","clamp","thatByte","nBytes","C_enc","enc","hexChars","bite","hexStr","hexStrLength","Latin1","latin1Chars","fromCharCode","latin1Str","latin1StrLength","Utf8","decodeURIComponent","escape","utf8Str","unescape","BufferedBlockAlgorithm","_data","_nDataBytes","_append","_process","doFlush","dataWords","dataSigBytes","blockSize","blockSizeBytes","nBlocksReady","_minBufferSize","nWordsReady","nBytesReady","min","_doProcessBlock","processedWords","C_algo","Hasher","cfg","_doReset","messageUpdate","hash","_doFinalize","_createHelper","hasher","_createHmacHelper","HMAC","algo","Base64","_map","base64Chars","byte1","byte2","byte3","triplet","j","paddingChar","base64Str","base64StrLength","paddingIndex","bits1","bits2","_hasher","hasherBlockSize","hasherBlockSizeBytes","oKey","_oKey","iKey","_iKey","oKeyWords","iKeyWords","innerHash","hmac","W","SHA1","_hash","M","H","n","t","nBitsTotal","nBitsLeft","floor","HmacSHA1","K","isPrime","sqrtN","factor","getFractionalBits","nPrime","SHA256","f","g","h","gamma0x","gamma0","gamma1x","gamma1","ch","maj","sigma0","sigma1","t1","t2","HmacSHA256","superInit","subInit","typedArray","Int8Array","Uint8ClampedArray","Int16Array","Uint16Array","Int32Array","Uint32Array","Float32Array","Float64Array","byteOffset","byteLength","typedArrayByteLength","s3","util","ALGORITHM_PARAM_NAME","AWS_PARAM_PREFIX","CREDENTIAL_PARAM_NAME","DATE_PARAM_NAME","REDUCED_REDUNDANCY_PARAM_NAME","REDUCED_REDUNDANCY_PARAM_VALUE","SERVER_SIDE_ENCRYPTION_PARAM_NAME","SERVER_SIDE_ENCRYPTION_PARAM_VALUE","SESSION_TOKEN_PARAM_NAME","V4_ALGORITHM_PARAM_VALUE","V4_SIGNATURE_PARAM_NAME","CASE_SENSITIVE_PARAM_NAMES","UNSIGNABLE_REST_HEADER_NAMES","UNPREFIXED_PARAM_NAMES","getBucket","bucket","patterns","pattern","_getPrefixedParamName","getPolicy","policy","conditions","date","drift","clockDrift","accessKey","acl","expectedStatus","sessionToken","successRedirectUrl","getSuccessRedirectAbsoluteUrl","minFileSize","maxFileSize","reducedRedundancy","region","serverSideEncryption","signatureVersion","expiration","getPolicyExpirationDate","Content-Type","success_action_status","success_action_redirect","getV4CredentialsString","getV4PolicyDate","awsParamName","enforceSizeLimits","refreshPolicyCredentials","newSessionToken","sessionTokenFound","oldCondIdx","oldCondObj","oldCondName","oldCondVal","generateAwsParams","signPolicyCallback","policyJson","awsParams","customParams","AWSAccessKeyId","policyAndSignature","updatedAccessKey","updatedSessionToken","signature","minSize","adjustedMinSize","adjustedMaxSize","adjustedDate","getPolicyDate","getCredentialsDate","getUTCFullYear","getUTCMonth","getUTCDate","_minutesToAdd_","pad","minutesToAdd","setMinutes","getMinutes","toISOString","number","getUTCHours","getUTCMinutes","getUTCSeconds","getUTCMilliseconds","parseIframeResponse","queryString","search","etag","targetAnchorContainer","encodeQueryStringParam","percentEncoded","uriEscape","uriEscapePath","nonTraditionalBasePublicApi","setUploadSuccessParams","_uploadSuccessParamsStore","setUploadSuccessEndpoint","_uploadSuccessEndpointStore","nonTraditionalBasePrivateApi","submitSuccessRequest","successAjaxRequester","onCompleteArgs","successEndpoint","successCustomHeaders","uploadSuccess","successMethod","uploadSuccessParams","fileParams","onSuccessFromServer","successRequestResult","_failedSuccessRequestCallbacks","onFailureFromServer","UploadSuccessAjaxRequester","_getEndpointSpecificParams","sendSuccessRequest","successRequestCallback","objectProperties","host","credentials","secretKey","iframeSupport","localBlankPagePath","onCredentialsExpired","setCredentials","_currentCredentials","_aclStore","_cannedKeys","_cannedBuckets","_buckets","_hosts","getKey","ignoreEmpty","setAcl","aclStore","_determineBucket","getHost","_determineHost","getKeyName","_determineKeyName","maxSizeLimit","oldParams","modifiedParams","paramName","credentialsProvider","onExpired","updateCredentials","_determineObjectPropertyValue","property","maybe","keynameLogic","onGetKeynameFailure","onGetKeynameSuccess","keyname","keynameToUse","_handleKeynameFunction","keynameFunc","successCallback","failureCallback","getResponseHeader","s3Key","s3Bucket","RequestSigner","handleSignatureReceived","responseJson","pendingSignatureData","pendingSignatures","signatureConstructor","invalid","expectingPolicy","generateHeaders","getStringToSignArtifacts","requestInfo","endOfUrl","signatureSpec","toSign","headerNames","headersStr","generateStringToSign","contentMd5","headerIndexesToRemove","headerName","headerIdx","hashedContent","v2","getStringToSign","v4","signedHeaders","getSignedHeaders","hashed","toSignRaw","raw","thisSignatureRequester","REQUEST_TYPE","MULTIPART_ABORT","uploadId","MULTIPART_INITIATE","MULTIPART_COMPLETE","MULTIPART_UPLOAD","partNum","getEncodedHashedPayload","Host","determineSignatureClientSide","toBeSigned","signatureEffort","updatedHeaders","getHeaders","getToSign","signatureArtifacts","signApiRequest","stringToSign","signPolicy","Authorization","getRequestDate","getEndOfUrl","headersWordArray","headersHmacSha1","headersHmacSha1Base64","policyStr","policyWordArray","base64Policy","policyHmacSha1","policyHmacSha1Base64","getCanonicalQueryString","endOfUri","encodedQueryParams","encodedQueryParamNames","queryStrings","queryParamIdx","canonicalQueryString","nameAndVal","paramVal","forEach","encodedQueryParamName","getCanonicalRequest","getCanonicalUri","onloadend","DONE","getScope","canonicalRequest","hashedRequest","scope","stringToSignTemplate","dateKey","dateRegionKey","dateRegionServiceKey","signingKey","headersPattern","matches","credentialPattern","credentialCondition","credential","condition","getSignature","queryParams","stringToSignRaw","constructStringToSign","artifacts","theHeaders","withUploadId","theUploadId","withContent","theContent","withContentType","theContentType","withPartNum","thePartNum","toUTCString","_artifacts_","handleSuccessResponse","parsedResponse","pendingRequests","successIndicator","failureIndicator","InitiateMultipartAjaxRequester","getSignatureAjaxRequester","getContentType","handleInitiateRequestComplete","uploadIdElements","messageElements","pendingInitiateRequests","domParser","DOMParser","responseDoc","parseFromString","CompleteMultipartAjaxRequester","handleCompleteRequestComplete","pendingCompleteRequests","bucketEls","keyEls","getCompleteRequestBody","etagEntries","implementation","createDocument","etagEntry","partEl","partNumEl","partNumTextEl","createTextNode","etagTextEl","etagEl","XMLSerializer","serializeToString","AbortMultipartAjaxRequester","handleAbortRequestComplete","awsErrorMsg","errorEls","onGetBucket","onGetHost","onGetKeyName","combine","etagMap","etags","requesters","completeMultipart","initHeaders","urlSafe","restSignature","put","domain","track","setup","uploadIdPromise","initiateMultipart","abortMultipart","policySignature","initParams","cachedBucket","cachedHost","shouldReset","keyName","encodedKey","parsedErrorProps","parseError","awsResponseXml","codeEls","messageEls","parsedDoc","errorDetails","existedInLocalStorage","baseStorageId","bucketName","isValidResponse","responseData","handleFinishedUpload","handleUpload","azure","AZURE_PARAM_PREFIX","_paramNameMatchesAzureParameter","getParamsAsHeaders","parseAzureError","codeTag","messageTag","errorTag","blobProperties","_cannedBlobNames","getBlobName","onGetBlobName","_determineBlobName","deleteBlob","_deleteBlob","blobNameOptionValue","fileExtension","blobNameToUse","blobName","relatedToCancel","deleteBlobSasUri","blobUriStore","deleteFileEndpointStore","getSasSuccess","sasUri","getSasFailure","DeleteBlob","getSas","GetSas","restRequestVerb","combineChunks","getSignedUrl","mimeType","blockIdEntries","putBlockList","determineBlobUrl","containerUrl","getBlobNameSuccess","getBlobNameFailure","getSasId","getSasXhr","determineBlobUrlSuccess","blobUrl","getSasForPutBlobOrBlock","determineBlobUrlFailure","azureError","minFileSizeForChunking","getBlobMetadata","putBlob","PutBlob","putBlock","PutBlock","PutBlockList","blockIdEntry","chunkingData","maybePossible","sasResponseReceived","requestPromises","blobUri","requestPromise","restVerb","bloburi","codes","endpoints","createBlockId","digits","zeros","paddedPartNum","btoa","blockId","createRequestBody","latestEl","latestTextEl","fileMimeType","registerXhrCallback","blockIdsXml","x-ms-blob-content-type"],"mappings":"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","file":"all.fine-uploader.min.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\"\"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq*/\n/**\n * Upload handler used that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to\n * a generic server.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.traditional = qq.traditional || {};\nqq.traditional.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log;\n\n /**\n * Returns json object received by iframe from server.\n */\n function getIframeContentJson(id, iframe) {\n /*jshint evil: true*/\n\n var response, doc, innerHtml;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n log(\"converting iframe's innerHTML to JSON\");\n log(\"innerHTML = \" + innerHtml);\n //plain text response may be wrapped in tag\n if (innerHtml && innerHtml.match(/^ 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.firefox()) {\n return !e.relatedTarget;\n }\n\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n e.preventDefault();\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n // dt.types.contains check is for firefox\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains(\"Files\")));\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n};\n","/*globals qq */\n/**\n * Defines the public API for FineUploader mode.\n */\n(function() {\n \"use strict\";\n\n qq.uiPublicApi = {\n addInitialFiles: function(cannedFileList) {\n this._parent.prototype.addInitialFiles.apply(this, arguments);\n this._templating.addCacheToDom();\n },\n\n clearStoredFiles: function() {\n this._parent.prototype.clearStoredFiles.apply(this, arguments);\n this._templating.clearFiles();\n },\n\n addExtraDropzone: function(element) {\n this._dnd && this._dnd.setupExtraDropzone(element);\n },\n\n removeExtraDropzone: function(element) {\n if (this._dnd) {\n return this._dnd.removeDropzone(element);\n }\n },\n\n getItemByFileId: function(id) {\n if (!this._templating.isHiddenForever(id)) {\n return this._templating.getFileContainer(id);\n }\n },\n\n reset: function() {\n this._parent.prototype.reset.apply(this, arguments);\n this._templating.reset();\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n if (this._dnd) {\n this._dnd.dispose();\n this._dnd = this._setupDragAndDrop();\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n\n this._setupClickAndEditEventHandlers();\n },\n\n setName: function(id, newName) {\n var formattedFilename = this._options.formatFileName(newName);\n\n this._parent.prototype.setName.apply(this, arguments);\n this._templating.updateFilename(id, formattedFilename);\n },\n\n pauseUpload: function(id) {\n var paused = this._parent.prototype.pauseUpload.apply(this, arguments);\n\n paused && this._templating.uploadPaused(id);\n return paused;\n },\n\n continueUpload: function(id) {\n var continued = this._parent.prototype.continueUpload.apply(this, arguments);\n\n continued && this._templating.uploadContinued(id);\n return continued;\n },\n\n getId: function(fileContainerOrChildEl) {\n return this._templating.getFileId(fileContainerOrChildEl);\n },\n\n getDropTarget: function(fileId) {\n var file = this.getFile(fileId);\n\n return file.qqDropTarget;\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploader mode.\n */\n qq.uiPrivateApi = {\n _getButton: function(buttonId) {\n var button = this._parent.prototype._getButton.apply(this, arguments);\n\n if (!button) {\n if (buttonId === this._defaultButtonId) {\n button = this._templating.getButton();\n }\n }\n\n return button;\n },\n\n _removeFileItem: function(fileId) {\n this._templating.removeFile(fileId);\n },\n\n _setupClickAndEditEventHandlers: function() {\n this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();\n\n // A better approach would be to check specifically for focusin event support by querying the DOM API,\n // but the DOMFocusIn event is not exposed as a property, so we have to resort to UA string sniffing.\n this._focusinEventSupported = !qq.firefox();\n\n if (this._isEditFilenameEnabled())\n {\n this._filenameClickHandler = this._bindFilenameClickEvent();\n this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();\n this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();\n }\n },\n\n _setupDragAndDrop: function() {\n var self = this,\n dropZoneElements = this._options.dragAndDrop.extraDropzones,\n templating = this._templating,\n defaultDropZone = templating.getDropZone();\n\n defaultDropZone && dropZoneElements.push(defaultDropZone);\n\n return new qq.DragAndDrop({\n dropZoneElements: dropZoneElements,\n allowMultipleItems: this._options.multiple,\n classes: {\n dropActive: this._options.classes.dropActive\n },\n callbacks: {\n processingDroppedFiles: function() {\n templating.showDropProcessing();\n },\n processingDroppedFilesComplete: function(files, targetEl) {\n templating.hideDropProcessing();\n\n qq.each(files, function(idx, file) {\n file.qqDropTarget = targetEl;\n });\n\n if (files.length) {\n self.addFiles(files, null, null);\n }\n },\n dropError: function(code, errorData) {\n self._itemError(code, errorData);\n },\n dropLog: function(message, level) {\n self.log(message, level);\n }\n }\n });\n },\n\n _bindFileButtonsClickEvent: function() {\n var self = this;\n\n return new qq.FileButtonsClickHandler({\n templating: this._templating,\n\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n\n onDeleteFile: function(fileId) {\n self.deleteFile(fileId);\n },\n\n onCancel: function(fileId) {\n self.cancel(fileId);\n },\n\n onRetry: function(fileId) {\n self.retry(fileId);\n },\n\n onPause: function(fileId) {\n self.pauseUpload(fileId);\n },\n\n onContinue: function(fileId) {\n self.continueUpload(fileId);\n },\n\n onGetName: function(fileId) {\n return self.getName(fileId);\n }\n });\n },\n\n _isEditFilenameEnabled: function() {\n /*jshint -W014 */\n return this._templating.isEditFilenamePossible()\n && !this._options.autoUpload\n && qq.FilenameClickHandler\n && qq.FilenameInputFocusHandler\n && qq.FilenameInputFocusHandler;\n },\n\n _filenameEditHandler: function() {\n var self = this,\n templating = this._templating;\n\n return {\n templating: templating,\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n onGetUploadStatus: function(fileId) {\n return self.getUploads({id: fileId}).status;\n },\n onGetName: function(fileId) {\n return self.getName(fileId);\n },\n onSetName: function(id, newName) {\n self.setName(id, newName);\n },\n onEditingStatusChange: function(id, isEditing) {\n var qqInput = qq(templating.getEditInput(id)),\n qqFileContainer = qq(templating.getFileContainer(id));\n\n if (isEditing) {\n qqInput.addClass(\"qq-editing\");\n templating.hideFilename(id);\n templating.hideEditIcon(id);\n }\n else {\n qqInput.removeClass(\"qq-editing\");\n templating.showFilename(id);\n templating.showEditIcon(id);\n }\n\n // Force IE8 and older to repaint\n qqFileContainer.addClass(\"qq-temp\").removeClass(\"qq-temp\");\n }\n };\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n this._parent.prototype._onUploadStatusChange.apply(this, arguments);\n\n if (this._isEditFilenameEnabled()) {\n // Status for a file exists before it has been added to the DOM, so we must be careful here.\n if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {\n this._templating.markFilenameEditable(id);\n this._templating.hideEditIcon(id);\n }\n }\n\n if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {\n this._templating.hideRetry(id);\n this._templating.setStatusText(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);\n }\n else if (newStatus === qq.status.UPLOAD_FAILED) {\n this._templating.hidePause(id);\n }\n },\n\n _bindFilenameInputFocusInEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusInHandler(spec);\n },\n\n _bindFilenameInputFocusEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusHandler(spec);\n },\n\n _bindFilenameClickEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameClickHandler(spec);\n },\n\n _storeForLater: function(id) {\n this._parent.prototype._storeForLater.apply(this, arguments);\n this._templating.hideSpinner(id);\n },\n\n _onAllComplete: function(successful, failed) {\n this._parent.prototype._onAllComplete.apply(this, arguments);\n this._templating.resetTotalProgress();\n },\n\n _onSubmit: function(id, name) {\n var file = this.getFile(id);\n\n if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {\n this._paramsStore.addReadOnly(id, {\n qqpath: file.qqPath\n });\n }\n\n this._parent.prototype._onSubmit.apply(this, arguments);\n this._addToList(id, name);\n },\n\n // The file item has been added to the DOM.\n _onSubmitted: function(id) {\n // If the edit filename feature is enabled, mark the filename element as \"editable\" and the associated edit icon\n if (this._isEditFilenameEnabled()) {\n this._templating.markFilenameEditable(id);\n this._templating.showEditIcon(id);\n\n // If the focusin event is not supported, we must add a focus handler to the newly create edit filename text input\n if (!this._focusinEventSupported) {\n this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));\n }\n }\n },\n\n // Update the progress bar & percentage as the file is uploaded\n _onProgress: function(id, name, loaded, total) {\n this._parent.prototype._onProgress.apply(this, arguments);\n\n this._templating.updateProgress(id, loaded, total);\n\n if (total === 0 || Math.round(loaded / total * 100) === 100) {\n this._templating.hideCancel(id);\n this._templating.hidePause(id);\n this._templating.hideProgress(id);\n this._templating.setStatusText(id, this._options.text.waitingForResponse);\n\n // If ~last byte was sent, display total file size\n this._displayFileSize(id);\n }\n else {\n // If still uploading, display percentage - total size is actually the total request(s) size\n this._displayFileSize(id, loaded, total);\n }\n },\n\n _onTotalProgress: function(loaded, total) {\n this._parent.prototype._onTotalProgress.apply(this, arguments);\n this._templating.updateTotalProgress(loaded, total);\n },\n\n _onComplete: function(id, name, result, xhr) {\n var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments),\n templating = this._templating,\n fileContainer = templating.getFileContainer(id),\n self = this;\n\n function completeUpload(result) {\n // If this file is not represented in the templating module, perhaps it was hidden intentionally.\n // If so, don't perform any UI-related tasks related to this file.\n if (!fileContainer) {\n return;\n }\n\n templating.setStatusText(id);\n\n qq(fileContainer).removeClass(self._classes.retrying);\n templating.hideProgress(id);\n\n if (self.getUploads({id: id}).status !== qq.status.UPLOAD_FAILED) {\n templating.hideCancel(id);\n }\n templating.hideSpinner(id);\n\n if (result.success) {\n self._markFileAsSuccessful(id);\n }\n else {\n qq(fileContainer).addClass(self._classes.fail);\n templating.showCancel(id);\n\n if (templating.isRetryPossible() && !self._preventRetries[id]) {\n qq(fileContainer).addClass(self._classes.retryable);\n templating.showRetry(id);\n }\n self._controlFailureTextDisplay(id, result);\n }\n }\n\n // The parent may need to perform some async operation before we can accurately determine the status of the upload.\n if (parentRetVal instanceof qq.Promise) {\n parentRetVal.done(function(newResult) {\n completeUpload(newResult);\n });\n\n }\n else {\n completeUpload(result);\n }\n\n return parentRetVal;\n },\n\n _markFileAsSuccessful: function(id) {\n var templating = this._templating;\n\n if (this._isDeletePossible()) {\n templating.showDeleteButton(id);\n }\n\n qq(templating.getFileContainer(id)).addClass(this._classes.success);\n\n this._maybeUpdateThumbnail(id);\n },\n\n _onUploadPrep: function(id) {\n this._parent.prototype._onUploadPrep.apply(this, arguments);\n this._templating.showSpinner(id);\n },\n\n _onUpload: function(id, name) {\n var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);\n\n this._templating.showSpinner(id);\n\n return parentRetVal;\n },\n\n _onUploadChunk: function(id, chunkData) {\n this._parent.prototype._onUploadChunk.apply(this, arguments);\n\n // Only display the pause button if we have finished uploading at least one chunk\n // & this file can be resumed\n if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {\n this._templating.allowPause(id);\n }\n },\n\n _onCancel: function(id, name) {\n this._parent.prototype._onCancel.apply(this, arguments);\n this._removeFileItem(id);\n\n if (this._getNotFinished() === 0) {\n this._templating.resetTotalProgress();\n }\n },\n\n _onBeforeAutoRetry: function(id) {\n var retryNumForDisplay, maxAuto, retryNote;\n\n this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);\n\n this._showCancelLink(id);\n\n if (this._options.retry.showAutoRetryNote) {\n retryNumForDisplay = this._autoRetries[id];\n maxAuto = this._options.retry.maxAutoAttempts;\n\n retryNote = this._options.retry.autoRetryNote.replace(/\\{retryNum\\}/g, retryNumForDisplay);\n retryNote = retryNote.replace(/\\{maxAuto\\}/g, maxAuto);\n\n this._templating.setStatusText(id, retryNote);\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);\n }\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {\n this._templating.resetProgress(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);\n this._templating.setStatusText(id);\n this._templating.showSpinner(id);\n this._showCancelLink(id);\n return true;\n }\n else {\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);\n this._templating.showRetry(id);\n return false;\n }\n },\n\n _onSubmitDelete: function(id) {\n var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);\n\n this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);\n },\n\n _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {\n if (this._options.deleteFile.forceConfirm) {\n this._showDeleteConfirm.apply(this, arguments);\n }\n else {\n this._sendDeleteRequest.apply(this, arguments);\n }\n },\n\n _onDeleteComplete: function(id, xhr, isError) {\n this._parent.prototype._onDeleteComplete.apply(this, arguments);\n\n this._templating.hideSpinner(id);\n\n if (isError) {\n this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);\n this._templating.showDeleteButton(id);\n }\n else {\n this._removeFileItem(id);\n }\n },\n\n _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {\n this._templating.hideDeleteButton(id);\n this._templating.showSpinner(id);\n this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);\n this._deleteHandler.sendDelete.apply(this, arguments);\n },\n\n _showDeleteConfirm: function(id, uuid, mandatedParams) {\n /*jshint -W004 */\n var fileName = this.getName(id),\n confirmMessage = this._options.deleteFile.confirmMessage.replace(/\\{filename\\}/g, fileName),\n uuid = this.getUuid(id),\n deleteRequestArgs = arguments,\n self = this,\n retVal;\n\n retVal = this._options.showConfirm(confirmMessage);\n\n if (qq.isGenericPromise(retVal)) {\n retVal.then(function() {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n });\n }\n else if (retVal !== false) {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n }\n },\n\n _addToList: function(id, name, canned) {\n var prependData,\n prependIndex = 0,\n dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled,\n record;\n\n if (this._options.display.prependFiles) {\n if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {\n prependIndex = this._filesInBatchAddedToUi - 1;\n }\n\n prependData = {\n index: prependIndex\n };\n }\n\n if (!canned) {\n if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {\n this._templating.disableCancel();\n }\n\n // Cancel all existing (previous) files and clear the list if this file is not part of\n // a scaled file group that has already been accepted, or if this file is not part of\n // a scaled file group at all.\n if (!this._options.multiple) {\n record = this.getUploads({id: id});\n\n this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;\n\n if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {\n this._handler.cancelAll();\n this._clearList();\n this._handledProxyGroup = null;\n }\n }\n }\n\n if (canned) {\n this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);\n }\n else {\n this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);\n }\n\n this._filesInBatchAddedToUi += 1;\n\n if (canned ||\n (this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading)) {\n\n this._displayFileSize(id);\n }\n },\n\n _clearList: function() {\n this._templating.clearFiles();\n this.clearStoredFiles();\n },\n\n _displayFileSize: function(id, loadedSize, totalSize) {\n var size = this.getSize(id),\n sizeForDisplay = this._formatSize(size);\n\n if (size >= 0) {\n if (loadedSize !== undefined && totalSize !== undefined) {\n sizeForDisplay = this._formatProgress(loadedSize, totalSize);\n }\n\n this._templating.updateSize(id, sizeForDisplay);\n }\n },\n\n _formatProgress: function(uploadedSize, totalSize) {\n var message = this._options.text.formatProgress;\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n r(\"{percent}\", Math.round(uploadedSize / totalSize * 100));\n r(\"{total_size}\", this._formatSize(totalSize));\n return message;\n },\n\n _controlFailureTextDisplay: function(id, response) {\n var mode, responseProperty, failureReason;\n\n mode = this._options.failedUploadTextDisplay.mode;\n responseProperty = this._options.failedUploadTextDisplay.responseProperty;\n\n if (mode === \"custom\") {\n failureReason = response[responseProperty];\n if (!failureReason) {\n failureReason = this._options.text.failUpload;\n }\n\n this._templating.setStatusText(id, failureReason);\n\n if (this._options.failedUploadTextDisplay.enableTooltip) {\n this._showTooltip(id, failureReason);\n }\n }\n else if (mode === \"default\") {\n this._templating.setStatusText(id, this._options.text.failUpload);\n }\n else if (mode !== \"none\") {\n this.log(\"failedUploadTextDisplay.mode value of '\" + mode + \"' is not valid\", \"warn\");\n }\n },\n\n _showTooltip: function(id, text) {\n this._templating.getFileContainer(id).title = text;\n },\n\n _showCancelLink: function(id) {\n if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {\n this._templating.showCancel(id);\n }\n },\n\n _itemError: function(code, name, item) {\n var message = this._parent.prototype._itemError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _batchError: function(message) {\n this._parent.prototype._batchError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _setupPastePrompt: function() {\n var self = this;\n\n this._options.callbacks.onPasteReceived = function() {\n var message = self._options.paste.namePromptMessage,\n defaultVal = self._options.paste.defaultName;\n\n return self._options.showPrompt(message, defaultVal);\n };\n },\n\n _fileOrBlobRejected: function(id, name) {\n this._totalFilesInBatch -= 1;\n this._parent.prototype._fileOrBlobRejected.apply(this, arguments);\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n this._totalFilesInBatch = items.length;\n this._filesInBatchAddedToUi = 0;\n this._parent.prototype._prepareItemsForUpload.apply(this, arguments);\n },\n\n _maybeUpdateThumbnail: function(fileId) {\n var thumbnailUrl = this._thumbnailUrls[fileId],\n fileStatus = this.getUploads({id: fileId}).status;\n\n if (fileStatus !== qq.status.DELETED &&\n (thumbnailUrl ||\n this._options.thumbnails.placeholders.waitUntilResponse ||\n !qq.supportedFeatures.imagePreviews)) {\n\n // This will replace the \"waiting\" placeholder with a \"preview not available\" placeholder\n // if called with a null thumbnailUrl.\n this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id = this._parent.prototype._addCannedFile.apply(this, arguments);\n\n this._addToList(id, this.getName(id), true);\n this._templating.hideSpinner(id);\n this._templating.hideCancel(id);\n this._markFileAsSuccessful(id);\n\n return id;\n },\n\n _setSize: function(id, newSize) {\n this._parent.prototype._setSize.apply(this, arguments);\n\n this._templating.updateSize(id, this._formatSize(newSize));\n },\n\n _sessionRequestComplete: function() {\n this._templating.addCacheToDom();\n this._parent.prototype._sessionRequestComplete.apply(this, arguments);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploader mode, which is a default UI w/ drag & drop uploading.\n */\nqq.FineUploader = function(o, namespace) {\n \"use strict\";\n\n var self = this;\n\n // By default this should inherit instance data from FineUploaderBasic, but this can be overridden\n // if the (internal) caller defines a different parent. The parent is also used by\n // the private and public API functions that need to delegate to a parent function.\n this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;\n this._parent.apply(this, arguments);\n\n // Options provided by FineUploader mode\n qq.extend(this._options, {\n element: null,\n\n button: null,\n\n listElement: null,\n\n dragAndDrop: {\n extraDropzones: [],\n reportDirectoryPaths: false\n },\n\n text: {\n formatProgress: \"{percent}% of {total_size}\",\n failUpload: \"Upload failed\",\n waitingForResponse: \"Processing...\",\n paused: \"Paused\"\n },\n\n template: \"qq-template\",\n\n classes: {\n retrying: \"qq-upload-retrying\",\n retryable: \"qq-upload-retryable\",\n success: \"qq-upload-success\",\n fail: \"qq-upload-fail\",\n editable: \"qq-editable\",\n hide: \"qq-hide\",\n dropActive: \"qq-upload-drop-area-active\"\n },\n\n failedUploadTextDisplay: {\n mode: \"default\", //default, custom, or none\n responseProperty: \"error\",\n enableTooltip: true\n },\n\n messages: {\n tooManyFilesError: \"You may only drop one file\",\n unsupportedBrowser: \"Unrecoverable error - this browser does not permit file uploading of any kind.\"\n },\n\n retry: {\n showAutoRetryNote: true,\n autoRetryNote: \"Retrying {retryNum}/{maxAuto}...\"\n },\n\n deleteFile: {\n forceConfirm: false,\n confirmMessage: \"Are you sure you want to delete {filename}?\",\n deletingStatusText: \"Deleting...\",\n deletingFailedText: \"Delete failed\"\n\n },\n\n display: {\n fileSizeOnSubmit: false,\n prependFiles: false\n },\n\n paste: {\n promptForName: false,\n namePromptMessage: \"Please name this image\"\n },\n\n thumbnails: {\n customResizer: null,\n maxCount: 0,\n placeholders: {\n waitUntilResponse: false,\n notAvailablePath: null,\n waitingPath: null\n },\n timeBetweenThumbs: 750\n },\n\n scaling: {\n hideScaled: false\n },\n\n showMessage: function(message) {\n if (self._templating.hasDialog(\"alert\")) {\n return self._templating.showDialog(\"alert\", message);\n }\n else {\n setTimeout(function() {\n window.alert(message);\n }, 0);\n }\n },\n\n showConfirm: function(message) {\n if (self._templating.hasDialog(\"confirm\")) {\n return self._templating.showDialog(\"confirm\", message);\n }\n else {\n return window.confirm(message);\n }\n },\n\n showPrompt: function(message, defaultValue) {\n if (self._templating.hasDialog(\"prompt\")) {\n return self._templating.showDialog(\"prompt\", message, defaultValue);\n }\n else {\n return window.prompt(message, defaultValue);\n }\n }\n }, true);\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._templating = new qq.Templating({\n log: qq.bind(this.log, this),\n templateIdOrEl: this._options.template,\n containerEl: this._options.element,\n fileContainerEl: this._options.listElement,\n button: this._options.button,\n imageGenerator: this._imageGenerator,\n classes: {\n hide: this._options.classes.hide,\n editable: this._options.classes.editable\n },\n limits: {\n maxThumbs: this._options.thumbnails.maxCount,\n timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs\n },\n placeholders: {\n waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,\n thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,\n waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath\n },\n text: this._options.text\n });\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);\n }\n else if (!qq.supportedFeatures.uploading || (this._options.cors.expected && !qq.supportedFeatures.uploadCors)) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowser);\n }\n else {\n this._wrapCallbacks();\n\n this._templating.render();\n\n this._classes = this._options.classes;\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._setupClickAndEditEventHandlers();\n\n if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {\n this._dnd = this._setupDragAndDrop();\n }\n\n if (this._options.paste.targetElement && this._options.paste.promptForName) {\n if (qq.PasteSupport) {\n this._setupPastePrompt();\n }\n else {\n this.log(\"Paste support module not found.\", \"error\");\n }\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n }\n};\n\n// Inherit the base public & private API methods\nqq.extend(qq.FineUploader.prototype, qq.basePublicApi);\nqq.extend(qq.FineUploader.prototype, qq.basePrivateApi);\n\n// Add the FineUploader/default UI public & private UI methods, which may override some base methods.\nqq.extend(qq.FineUploader.prototype, qq.uiPublicApi);\nqq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);\n","/* globals qq */\n/* jshint -W065 */\n/**\n * Module responsible for rendering all Fine Uploader UI templates. This module also asserts at least\n * a limited amount of control over the template elements after they are added to the DOM.\n * Wherever possible, this module asserts total control over template elements present in the DOM.\n *\n * @param spec Specification object used to control various templating behaviors\n * @constructor\n */\nqq.Templating = function(spec) {\n \"use strict\";\n\n var FILE_ID_ATTR = \"qq-file-id\",\n FILE_CLASS_PREFIX = \"qq-file-id-\",\n THUMBNAIL_MAX_SIZE_ATTR = \"qq-max-size\",\n THUMBNAIL_SERVER_SCALE_ATTR = \"qq-server-scale\",\n // This variable is duplicated in the DnD module since it can function as a standalone as well\n HIDE_DROPZONE_ATTR = \"qq-hide-dropzone\",\n DROPZPONE_TEXT_ATTR = \"qq-drop-area-text\",\n IN_PROGRESS_CLASS = \"qq-in-progress\",\n HIDDEN_FOREVER_CLASS = \"qq-hidden-forever\",\n fileBatch = {\n content: document.createDocumentFragment(),\n map: {}\n },\n isCancelDisabled = false,\n generatedThumbnails = 0,\n thumbnailQueueMonitorRunning = false,\n thumbGenerationQueue = [],\n thumbnailMaxSize = -1,\n options = {\n log: null,\n limits: {\n maxThumbs: 0,\n timeBetweenThumbs: 750\n },\n templateIdOrEl: \"qq-template\",\n containerEl: null,\n fileContainerEl: null,\n button: null,\n imageGenerator: null,\n classes: {\n hide: \"qq-hide\",\n editable: \"qq-editable\"\n },\n placeholders: {\n waitUntilUpdate: false,\n thumbnailNotAvailable: null,\n waitingForThumbnail: null\n },\n text: {\n paused: \"Paused\"\n }\n },\n selectorClasses = {\n button: \"qq-upload-button-selector\",\n alertDialog: \"qq-alert-dialog-selector\",\n dialogCancelButton: \"qq-cancel-button-selector\",\n confirmDialog: \"qq-confirm-dialog-selector\",\n dialogMessage: \"qq-dialog-message-selector\",\n dialogOkButton: \"qq-ok-button-selector\",\n promptDialog: \"qq-prompt-dialog-selector\",\n uploader: \"qq-uploader-selector\",\n drop: \"qq-upload-drop-area-selector\",\n list: \"qq-upload-list-selector\",\n progressBarContainer: \"qq-progress-bar-container-selector\",\n progressBar: \"qq-progress-bar-selector\",\n totalProgressBarContainer: \"qq-total-progress-bar-container-selector\",\n totalProgressBar: \"qq-total-progress-bar-selector\",\n file: \"qq-upload-file-selector\",\n spinner: \"qq-upload-spinner-selector\",\n size: \"qq-upload-size-selector\",\n cancel: \"qq-upload-cancel-selector\",\n pause: \"qq-upload-pause-selector\",\n continueButton: \"qq-upload-continue-selector\",\n deleteButton: \"qq-upload-delete-selector\",\n retry: \"qq-upload-retry-selector\",\n statusText: \"qq-upload-status-text-selector\",\n editFilenameInput: \"qq-edit-filename-selector\",\n editNameIcon: \"qq-edit-filename-icon-selector\",\n dropText: \"qq-upload-drop-area-text-selector\",\n dropProcessing: \"qq-drop-processing-selector\",\n dropProcessingSpinner: \"qq-drop-processing-spinner-selector\",\n thumbnail: \"qq-thumbnail-selector\"\n },\n previewGeneration = {},\n cachedThumbnailNotAvailableImg = new qq.Promise(),\n cachedWaitingForThumbnailImg = new qq.Promise(),\n log,\n isEditElementsExist,\n isRetryElementExist,\n templateHtml,\n container,\n fileList,\n showThumbnails,\n serverScale,\n\n // During initialization of the templating module we should cache any\n // placeholder images so we can quickly swap them into the file list on demand.\n // Any placeholder images that cannot be loaded/found are simply ignored.\n cacheThumbnailPlaceholders = function() {\n var notAvailableUrl = options.placeholders.thumbnailNotAvailable,\n waitingUrl = options.placeholders.waitingForThumbnail,\n spec = {\n maxSize: thumbnailMaxSize,\n scale: serverScale\n };\n\n if (showThumbnails) {\n if (notAvailableUrl) {\n options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedThumbnailNotAvailableImg.success(updatedImg);\n },\n function() {\n cachedThumbnailNotAvailableImg.failure();\n log(\"Problem loading 'not available' placeholder image at \" + notAvailableUrl, \"error\");\n }\n );\n }\n else {\n cachedThumbnailNotAvailableImg.failure();\n }\n\n if (waitingUrl) {\n options.imageGenerator.generate(waitingUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedWaitingForThumbnailImg.success(updatedImg);\n },\n function() {\n cachedWaitingForThumbnailImg.failure();\n log(\"Problem loading 'waiting for thumbnail' placeholder image at \" + waitingUrl, \"error\");\n }\n );\n }\n else {\n cachedWaitingForThumbnailImg.failure();\n }\n }\n },\n\n // Displays a \"waiting for thumbnail\" type placeholder image\n // iff we were able to load it during initialization of the templating module.\n displayWaitingImg = function(thumbnail) {\n var waitingImgPlacement = new qq.Promise();\n\n cachedWaitingForThumbnailImg.then(function(img) {\n maybeScalePlaceholderViaCss(img, thumbnail);\n /* jshint eqnull:true */\n if (!thumbnail.src) {\n thumbnail.src = img.src;\n thumbnail.onload = function() {\n thumbnail.onload = null;\n show(thumbnail);\n waitingImgPlacement.success();\n };\n }\n else {\n waitingImgPlacement.success();\n }\n }, function() {\n // In some browsers (such as IE9 and older) an img w/out a src attribute\n // are displayed as \"broken\" images, so we should just hide the img tag\n // if we aren't going to display the \"waiting\" placeholder.\n hide(thumbnail);\n waitingImgPlacement.success();\n });\n\n return waitingImgPlacement;\n },\n\n generateNewPreview = function(id, blob, spec) {\n var thumbnail = getThumbnail(id);\n\n log(\"Generating new thumbnail for \" + id);\n blob.qqThumbnailId = id;\n\n return options.imageGenerator.generate(blob, thumbnail, spec).then(\n function() {\n generatedThumbnails++;\n show(thumbnail);\n previewGeneration[id].success();\n },\n function() {\n previewGeneration[id].failure();\n\n // Display the \"not available\" placeholder img only if we are\n // not expecting a thumbnail at a later point, such as in a server response.\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n }\n });\n },\n\n generateNextQueuedPreview = function() {\n if (thumbGenerationQueue.length) {\n thumbnailQueueMonitorRunning = true;\n\n var queuedThumbRequest = thumbGenerationQueue.shift();\n\n if (queuedThumbRequest.update) {\n processUpdateQueuedPreviewRequest(queuedThumbRequest);\n }\n else {\n processNewQueuedPreviewRequest(queuedThumbRequest);\n }\n }\n else {\n thumbnailQueueMonitorRunning = false;\n }\n },\n\n getCancel = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.cancel);\n },\n\n getContinue = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.continueButton);\n },\n\n getDialog = function(type) {\n return getTemplateEl(container, selectorClasses[type + \"Dialog\"]);\n },\n\n getDelete = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.deleteButton);\n },\n\n getDropProcessing = function() {\n return getTemplateEl(container, selectorClasses.dropProcessing);\n },\n\n getEditIcon = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editNameIcon);\n },\n\n getFile = function(id) {\n return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);\n },\n\n getFilename = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.file);\n },\n\n getPause = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.pause);\n },\n\n getProgress = function(id) {\n /* jshint eqnull:true */\n // Total progress bar\n if (id == null) {\n return getTemplateEl(container, selectorClasses.totalProgressBarContainer) ||\n getTemplateEl(container, selectorClasses.totalProgressBar);\n }\n\n // Per-file progress bar\n return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) ||\n getTemplateEl(getFile(id), selectorClasses.progressBar);\n },\n\n getRetry = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.retry);\n },\n\n getSize = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.size);\n },\n\n getSpinner = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.spinner);\n },\n\n getTemplateEl = function(context, cssClass) {\n return context && qq(context).getFirstByClass(cssClass);\n },\n\n getThumbnail = function(id) {\n return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);\n },\n\n hide = function(el) {\n el && qq(el).addClass(options.classes.hide);\n },\n\n // Ensures a placeholder image does not exceed any max size specified\n // via `style` attribute properties iff was not used to scale\n // the placeholder AND the target doesn't already have these `style` attribute properties set.\n maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {\n var maxWidth = placeholder.style.maxWidth,\n maxHeight = placeholder.style.maxHeight;\n\n if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {\n qq(thumbnail).css({\n maxWidth: maxWidth,\n maxHeight: maxHeight\n });\n }\n },\n\n // Displays a \"thumbnail not available\" type placeholder image\n // iff we were able to load this placeholder during initialization\n // of the templating module or after preview generation has failed.\n maybeSetDisplayNotAvailableImg = function(id, thumbnail) {\n var previewing = previewGeneration[id] || new qq.Promise().failure(),\n notAvailableImgPlacement = new qq.Promise();\n\n cachedThumbnailNotAvailableImg.then(function(img) {\n previewing.then(\n function() {\n notAvailableImgPlacement.success();\n },\n function() {\n maybeScalePlaceholderViaCss(img, thumbnail);\n\n thumbnail.onload = function() {\n thumbnail.onload = null;\n notAvailableImgPlacement.success();\n };\n\n thumbnail.src = img.src;\n show(thumbnail);\n }\n );\n });\n\n return notAvailableImgPlacement;\n },\n\n /**\n * Grabs the HTML from the script tag holding the template markup. This function will also adjust\n * some internally-tracked state variables based on the contents of the template.\n * The template is filtered so that irrelevant elements (such as the drop zone if DnD is not supported)\n * are omitted from the DOM. Useful errors will be thrown if the template cannot be parsed.\n *\n * @returns {{template: *, fileTemplate: *}} HTML for the top-level file items templates\n */\n parseAndGetTemplate = function() {\n var scriptEl,\n scriptHtml,\n fileListNode,\n tempTemplateEl,\n fileListHtml,\n defaultButton,\n dropArea,\n thumbnail,\n dropProcessing,\n dropTextEl,\n uploaderEl;\n\n log(\"Parsing template\");\n\n /*jshint -W116*/\n if (options.templateIdOrEl == null) {\n throw new Error(\"You MUST specify either a template element or ID!\");\n }\n\n // Grab the contents of the script tag holding the template.\n if (qq.isString(options.templateIdOrEl)) {\n scriptEl = document.getElementById(options.templateIdOrEl);\n\n if (scriptEl === null) {\n throw new Error(qq.format(\"Cannot find template script at ID '{}'!\", options.templateIdOrEl));\n }\n\n scriptHtml = scriptEl.innerHTML;\n }\n else {\n if (options.templateIdOrEl.innerHTML === undefined) {\n throw new Error(\"You have specified an invalid value for the template option! \" +\n \"It must be an ID or an Element.\");\n }\n\n scriptHtml = options.templateIdOrEl.innerHTML;\n }\n\n scriptHtml = qq.trimStr(scriptHtml);\n tempTemplateEl = document.createElement(\"div\");\n tempTemplateEl.appendChild(qq.toElement(scriptHtml));\n uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);\n\n // Don't include the default template button in the DOM\n // if an alternate button container has been specified.\n if (options.button) {\n defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);\n if (defaultButton) {\n qq(defaultButton).remove();\n }\n }\n\n // Omit the drop processing element from the DOM if DnD is not supported by the UA,\n // or the drag and drop module is not found.\n // NOTE: We are consciously not removing the drop zone if the UA doesn't support DnD\n // to support layouts where the drop zone is also a container for visible elements,\n // such as the file list.\n if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {\n dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);\n if (dropProcessing) {\n qq(dropProcessing).remove();\n }\n }\n\n dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);\n\n // If DnD is not available then remove\n // it from the DOM as well.\n if (dropArea && !qq.DragAndDrop) {\n log(\"DnD module unavailable.\", \"info\");\n qq(dropArea).remove();\n }\n\n if (!qq.supportedFeatures.fileDrop) {\n // don't display any \"drop files to upload\" background text\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {\n // If there is a drop area defined in the template, and the current UA doesn't support DnD,\n // and the drop area is marked as \"hide before enter\", ensure it is hidden as the DnD module\n // will not do this (since we will not be loading the DnD module)\n qq(dropArea).css({\n display: \"none\"\n });\n }\n }\n else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {\n dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);\n dropTextEl && qq(dropTextEl).remove();\n }\n\n // Ensure the `showThumbnails` flag is only set if the thumbnail element\n // is present in the template AND the current UA is capable of generating client-side previews.\n thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);\n if (!showThumbnails) {\n thumbnail && qq(thumbnail).remove();\n }\n else if (thumbnail) {\n thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));\n // Only enforce max size if the attr value is non-zero\n thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;\n\n serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);\n }\n showThumbnails = showThumbnails && thumbnail;\n\n isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;\n isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;\n\n fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);\n /*jshint -W116*/\n if (fileListNode == null) {\n throw new Error(\"Could not find the file list container in the template!\");\n }\n\n fileListHtml = fileListNode.innerHTML;\n fileListNode.innerHTML = \"\";\n\n // We must call `createElement` in IE8 in order to target and hide any via CSS\n if (tempTemplateEl.getElementsByTagName(\"DIALOG\").length) {\n document.createElement(\"dialog\");\n }\n\n log(\"Template parsing complete\");\n\n return {\n template: qq.trimStr(tempTemplateEl.innerHTML),\n fileTemplate: qq.trimStr(fileListHtml)\n };\n },\n\n prependFile = function(el, index, fileList) {\n var parentEl = fileList,\n beforeEl = parentEl.firstChild;\n\n if (index > 0) {\n beforeEl = qq(parentEl).children()[index].nextSibling;\n\n }\n\n parentEl.insertBefore(el, beforeEl);\n },\n\n processNewQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n optFileOrBlob = queuedThumbRequest.optFileOrBlob,\n relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n maxSize: thumbnailMaxSize,\n orient: true,\n scale: true\n };\n\n if (qq.supportedFeatures.imagePreviews) {\n if (thumbnail) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n displayWaitingImg(thumbnail).done(function() {\n previewGeneration[id] = new qq.Promise();\n\n previewGeneration[id].done(function() {\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n });\n\n /* jshint eqnull: true */\n // If we've already generated an for this file, use the one that exists,\n // don't waste resources generating a new one.\n if (relatedThumbnailId != null) {\n useCachedPreview(id, relatedThumbnailId);\n }\n else {\n generateNewPreview(id, optFileOrBlob, spec);\n }\n });\n }\n }\n // File element in template may have been removed, so move on to next item in queue\n else {\n generateNextQueuedPreview();\n }\n }\n else if (thumbnail) {\n displayWaitingImg(thumbnail);\n generateNextQueuedPreview();\n }\n },\n\n processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n thumbnailUrl = queuedThumbRequest.thumbnailUrl,\n showWaitingImg = queuedThumbRequest.showWaitingImg,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n scale: serverScale,\n maxSize: thumbnailMaxSize\n };\n\n if (thumbnail) {\n if (thumbnailUrl) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n if (showWaitingImg) {\n displayWaitingImg(thumbnail);\n }\n\n return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(\n function() {\n show(thumbnail);\n generatedThumbnails++;\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n },\n\n function() {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n }\n );\n }\n }\n else {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n }\n },\n\n setProgressBarWidth = function(id, percent) {\n var bar = getProgress(id),\n /* jshint eqnull:true */\n progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;\n\n if (bar && !qq(bar).hasClass(progressBarSelector)) {\n bar = qq(bar).getFirstByClass(progressBarSelector);\n }\n\n if (bar) {\n qq(bar).css({width: percent + \"%\"});\n bar.setAttribute(\"aria-valuenow\", percent);\n }\n },\n\n show = function(el) {\n el && qq(el).removeClass(options.classes.hide);\n },\n\n useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {\n var targetThumbnail = getThumbnail(targetThumbnailId),\n cachedThumbnail = getThumbnail(cachedThumbnailId);\n\n log(qq.format(\"ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.\", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));\n\n // Generation of the related thumbnail may still be in progress, so, wait until it is done.\n previewGeneration[cachedThumbnailId].then(function() {\n generatedThumbnails++;\n previewGeneration[targetThumbnailId].success();\n log(qq.format(\"Now using previously generated thumbnail created for ID {} on ID {}.\", cachedThumbnailId, targetThumbnailId));\n targetThumbnail.src = cachedThumbnail.src;\n show(targetThumbnail);\n },\n function() {\n previewGeneration[targetThumbnailId].failure();\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);\n }\n });\n };\n\n qq.extend(options, spec);\n log = options.log;\n\n // No need to worry about conserving CPU or memory on older browsers,\n // since there is no ability to preview, and thumbnail display is primitive and quick.\n if (!qq.supportedFeatures.imagePreviews) {\n options.limits.timeBetweenThumbs = 0;\n options.limits.maxThumbs = 0;\n }\n\n container = options.containerEl;\n showThumbnails = options.imageGenerator !== undefined;\n templateHtml = parseAndGetTemplate();\n\n cacheThumbnailPlaceholders();\n\n qq.extend(this, {\n render: function() {\n log(\"Rendering template in DOM.\");\n\n generatedThumbnails = 0;\n\n container.innerHTML = templateHtml.template;\n hide(getDropProcessing());\n this.hideTotalProgress();\n fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);\n\n log(\"Template rendering complete\");\n },\n\n renderFailure: function(message) {\n var cantRenderEl = qq.toElement(message);\n container.innerHTML = \"\";\n container.appendChild(cantRenderEl);\n },\n\n reset: function() {\n this.render();\n },\n\n clearFiles: function() {\n fileList.innerHTML = \"\";\n },\n\n disableCancel: function() {\n isCancelDisabled = true;\n },\n\n addFile: function(id, name, prependInfo, hideForever, batch) {\n var fileEl = qq.toElement(templateHtml.fileTemplate),\n fileNameEl = getTemplateEl(fileEl, selectorClasses.file),\n uploaderEl = getTemplateEl(container, selectorClasses.uploader),\n fileContainer = batch ? fileBatch.content : fileList,\n thumb;\n\n if (batch) {\n fileBatch.map[id] = fileEl;\n }\n\n qq(fileEl).addClass(FILE_CLASS_PREFIX + id);\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (fileNameEl) {\n qq(fileNameEl).setText(name);\n fileNameEl.setAttribute(\"title\", name);\n }\n\n fileEl.setAttribute(FILE_ID_ATTR, id);\n\n if (prependInfo) {\n prependFile(fileEl, prependInfo.index, fileContainer);\n }\n else {\n fileContainer.appendChild(fileEl);\n }\n\n if (hideForever) {\n fileEl.style.display = \"none\";\n qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);\n }\n else {\n hide(getProgress(id));\n hide(getSize(id));\n hide(getDelete(id));\n hide(getRetry(id));\n hide(getPause(id));\n hide(getContinue(id));\n\n if (isCancelDisabled) {\n this.hideCancel(id);\n }\n\n thumb = getThumbnail(id);\n if (thumb && !thumb.src) {\n cachedWaitingForThumbnailImg.then(function(waitingImg) {\n thumb.src = waitingImg.src;\n if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {\n qq(thumb).css({\n maxHeight: waitingImg.style.maxHeight,\n maxWidth: waitingImg.style.maxWidth\n });\n }\n\n show(thumb);\n });\n }\n }\n },\n\n addFileToCache: function(id, name, prependInfo, hideForever) {\n this.addFile(id, name, prependInfo, hideForever, true);\n },\n\n addCacheToDom: function() {\n fileList.appendChild(fileBatch.content);\n fileBatch.content = document.createDocumentFragment();\n fileBatch.map = {};\n },\n\n removeFile: function(id) {\n qq(getFile(id)).remove();\n },\n\n getFileId: function(el) {\n var currentNode = el;\n\n if (currentNode) {\n /*jshint -W116*/\n while (currentNode.getAttribute(FILE_ID_ATTR) == null) {\n currentNode = currentNode.parentNode;\n }\n\n return parseInt(currentNode.getAttribute(FILE_ID_ATTR));\n }\n },\n\n getFileList: function() {\n return fileList;\n },\n\n markFilenameEditable: function(id) {\n var filename = getFilename(id);\n\n filename && qq(filename).addClass(options.classes.editable);\n },\n\n updateFilename: function(id, name) {\n var filenameEl = getFilename(id);\n\n if (filenameEl) {\n qq(filenameEl).setText(name);\n filenameEl.setAttribute(\"title\", name);\n }\n },\n\n hideFilename: function(id) {\n hide(getFilename(id));\n },\n\n showFilename: function(id) {\n show(getFilename(id));\n },\n\n isFileName: function(el) {\n return qq(el).hasClass(selectorClasses.file);\n },\n\n getButton: function() {\n return options.button || getTemplateEl(container, selectorClasses.button);\n },\n\n hideDropProcessing: function() {\n hide(getDropProcessing());\n },\n\n showDropProcessing: function() {\n show(getDropProcessing());\n },\n\n getDropZone: function() {\n return getTemplateEl(container, selectorClasses.drop);\n },\n\n isEditFilenamePossible: function() {\n return isEditElementsExist;\n },\n\n hideRetry: function(id) {\n hide(getRetry(id));\n },\n\n isRetryPossible: function() {\n return isRetryElementExist;\n },\n\n showRetry: function(id) {\n show(getRetry(id));\n },\n\n getFileContainer: function(id) {\n return getFile(id);\n },\n\n showEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).addClass(options.classes.editable);\n },\n\n isHiddenForever: function(id) {\n return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);\n },\n\n hideEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).removeClass(options.classes.editable);\n },\n\n isEditIcon: function(el) {\n return qq(el).hasClass(selectorClasses.editNameIcon, true);\n },\n\n getEditInput: function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);\n },\n\n isEditInput: function(el) {\n return qq(el).hasClass(selectorClasses.editFilenameInput, true);\n },\n\n updateProgress: function(id, loaded, total) {\n var bar = getProgress(id),\n percent;\n\n if (bar && total > 0) {\n percent = Math.round(loaded / total * 100);\n\n if (percent === 100) {\n hide(bar);\n }\n else {\n show(bar);\n }\n\n setProgressBarWidth(id, percent);\n }\n },\n\n updateTotalProgress: function(loaded, total) {\n this.updateProgress(null, loaded, total);\n },\n\n hideProgress: function(id) {\n var bar = getProgress(id);\n\n bar && hide(bar);\n },\n\n hideTotalProgress: function() {\n this.hideProgress();\n },\n\n resetProgress: function(id) {\n setProgressBarWidth(id, 0);\n this.hideTotalProgress(id);\n },\n\n resetTotalProgress: function() {\n this.resetProgress();\n },\n\n showCancel: function(id) {\n if (!isCancelDisabled) {\n var cancel = getCancel(id);\n\n cancel && qq(cancel).removeClass(options.classes.hide);\n }\n },\n\n hideCancel: function(id) {\n hide(getCancel(id));\n },\n\n isCancel: function(el) {\n return qq(el).hasClass(selectorClasses.cancel, true);\n },\n\n allowPause: function(id) {\n show(getPause(id));\n hide(getContinue(id));\n },\n\n uploadPaused: function(id) {\n this.setStatusText(id, options.text.paused);\n this.allowContinueButton(id);\n hide(getSpinner(id));\n },\n\n hidePause: function(id) {\n hide(getPause(id));\n },\n\n isPause: function(el) {\n return qq(el).hasClass(selectorClasses.pause, true);\n },\n\n isContinueButton: function(el) {\n return qq(el).hasClass(selectorClasses.continueButton, true);\n },\n\n allowContinueButton: function(id) {\n show(getContinue(id));\n hide(getPause(id));\n },\n\n uploadContinued: function(id) {\n this.setStatusText(id, \"\");\n this.allowPause(id);\n show(getSpinner(id));\n },\n\n showDeleteButton: function(id) {\n show(getDelete(id));\n },\n\n hideDeleteButton: function(id) {\n hide(getDelete(id));\n },\n\n isDeleteButton: function(el) {\n return qq(el).hasClass(selectorClasses.deleteButton, true);\n },\n\n isRetry: function(el) {\n return qq(el).hasClass(selectorClasses.retry, true);\n },\n\n updateSize: function(id, text) {\n var size = getSize(id);\n\n if (size) {\n show(size);\n qq(size).setText(text);\n }\n },\n\n setStatusText: function(id, text) {\n var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);\n\n if (textEl) {\n /*jshint -W116*/\n if (text == null) {\n qq(textEl).clearText();\n }\n else {\n qq(textEl).setText(text);\n }\n }\n },\n\n hideSpinner: function(id) {\n qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);\n hide(getSpinner(id));\n },\n\n showSpinner: function(id) {\n qq(getFile(id)).addClass(IN_PROGRESS_CLASS);\n show(getSpinner(id));\n },\n\n generatePreview: function(id, optFileOrBlob, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({id: id, customResizeFunction: customResizeFunction, optFileOrBlob: optFileOrBlob});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({customResizeFunction: customResizeFunction, update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n hasDialog: function(type) {\n return qq.supportedFeatures.dialogElement && !!getDialog(type);\n },\n\n showDialog: function(type, message, defaultValue) {\n var dialog = getDialog(type),\n messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage),\n inputEl = dialog.getElementsByTagName(\"INPUT\")[0],\n cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton),\n okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton),\n promise = new qq.Promise(),\n\n closeHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.removeEventListener(\"click\", okClickHandler);\n promise.failure();\n },\n\n cancelClickHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n dialog.close();\n },\n\n okClickHandler = function() {\n dialog.removeEventListener(\"close\", closeHandler);\n okBtn.removeEventListener(\"click\", okClickHandler);\n dialog.close();\n\n promise.success(inputEl && inputEl.value);\n };\n\n dialog.addEventListener(\"close\", closeHandler);\n cancelBtn.addEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.addEventListener(\"click\", okClickHandler);\n\n if (inputEl) {\n inputEl.value = defaultValue;\n }\n messageEl.textContent = message;\n\n dialog.showModal();\n\n return promise;\n }\n });\n};\n","/*globals qq */\n// Base handler for UI (FineUploader mode) events.\n// Some more specific handlers inherit from this one.\nqq.UiEventHandler = function(s, protectedApi) {\n \"use strict\";\n\n var disposer = new qq.DisposeSupport(),\n spec = {\n eventType: \"click\",\n attachTo: null,\n onHandled: function(target, event) {}\n };\n\n // This makes up the \"public\" API methods that will be accessible\n // to instances constructing a base or child handler\n qq.extend(this, {\n addHandler: function(element) {\n addHandler(element);\n },\n\n dispose: function() {\n disposer.dispose();\n }\n });\n\n function addHandler(element) {\n disposer.attach(element, spec.eventType, function(event) {\n // Only in IE: the `event` is a property of the `window`.\n event = event || window.event;\n\n // On older browsers, we must check the `srcElement` instead of the `target`.\n var target = event.target || event.srcElement;\n\n spec.onHandled(target, event);\n });\n }\n\n // These make up the \"protected\" API methods that children of this base handler will utilize.\n qq.extend(protectedApi, {\n getFileIdFromItem: function(item) {\n return item.qqFileId;\n },\n\n getDisposeSupport: function() {\n return disposer;\n }\n });\n\n qq.extend(spec, s);\n\n if (spec.attachTo) {\n addHandler(spec.attachTo);\n }\n};\n","/* global qq */\nqq.FileButtonsClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n onDeleteFile: function(fileId) {},\n onCancel: function(fileId) {},\n onRetry: function(fileId) {},\n onPause: function(fileId) {},\n onContinue: function(fileId) {},\n onGetName: function(fileId) {}\n },\n buttonHandlers = {\n cancel: function(id) { spec.onCancel(id); },\n retry: function(id) { spec.onRetry(id); },\n deleteButton: function(id) { spec.onDeleteFile(id); },\n pause: function(id) { spec.onPause(id); },\n continueButton: function(id) { spec.onContinue(id); }\n };\n\n function examineEvent(target, event) {\n qq.each(buttonHandlers, function(buttonType, handler) {\n var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1),\n fileId;\n\n if (spec.templating[\"is\" + firstLetterCapButtonType](target)) {\n fileId = spec.templating.getFileId(target);\n qq.preventDefault(event);\n spec.log(qq.format(\"Detected valid file button click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n handler(fileId);\n return false;\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect click events on filename display elements.\nqq.FilenameClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n classes: {\n file: \"qq-upload-file\",\n editNameIcon: \"qq-edit-filename-icon\"\n },\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {}\n };\n\n qq.extend(spec, s);\n\n // This will be called by the parent handler when a `click` event is received on the list element.\n function examineEvent(target, event) {\n if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n // We only allow users to change filenames of files that have been submitted but not yet uploaded.\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n qq.preventDefault(event);\n\n inheritedInternalApi.handleFilenameEdit(fileId, target, true);\n }\n }\n }\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect focusin events on file edit input elements.\nqq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n onGetUploadStatus: function(fileId) {},\n log: function(message, lvl) {}\n };\n\n if (!inheritedInternalApi) {\n inheritedInternalApi = {};\n }\n\n // This will be called by the parent handler when a `focusin` event is received on the list element.\n function handleInputFocus(target, event) {\n if (spec.templating.isEditInput(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename input focus event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n inheritedInternalApi.handleFilenameEdit(fileId, target);\n }\n }\n }\n\n spec.eventType = \"focusin\";\n spec.onHandled = handleInputFocus;\n\n qq.extend(spec, s);\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n/**\n * Child of FilenameInputFocusInHandler. Used to detect focus events on file edit input elements. This child module is only\n * needed for UAs that do not support the focusin event. Currently, only Firefox lacks this event.\n *\n * @param spec Overrides for default specifications\n */\nqq.FilenameInputFocusHandler = function(spec) {\n \"use strict\";\n\n spec.eventType = \"focus\";\n spec.attachTo = null;\n\n qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));\n};\n","/*globals qq */\n// Handles edit-related events on a file item (FineUploader mode). This is meant to be a parent handler.\n// Children will delegate to this handler when specific edit-related actions are detected.\nqq.FilenameEditHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n log: function(message, lvl) {},\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {},\n onSetName: function(fileId, newName) {},\n onEditingStatusChange: function(fileId, isEditing) {}\n };\n\n function getFilenameSansExtension(fileId) {\n var filenameSansExt = spec.onGetName(fileId),\n extIdx = filenameSansExt.lastIndexOf(\".\");\n\n if (extIdx > 0) {\n filenameSansExt = filenameSansExt.substr(0, extIdx);\n }\n\n return filenameSansExt;\n }\n\n function getOriginalExtension(fileId) {\n var origName = spec.onGetName(fileId);\n return qq.getExtension(origName);\n }\n\n // Callback iff the name has been changed\n function handleNameUpdate(newFilenameInputEl, fileId) {\n var newName = newFilenameInputEl.value,\n origExtension;\n\n if (newName !== undefined && qq.trimStr(newName).length > 0) {\n origExtension = getOriginalExtension(fileId);\n\n if (origExtension !== undefined) {\n newName = newName + \".\" + origExtension;\n }\n\n spec.onSetName(fileId, newName);\n }\n\n spec.onEditingStatusChange(fileId, false);\n }\n\n // The name has been updated if the filename edit input loses focus.\n function registerInputBlurHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"blur\", function() {\n handleNameUpdate(inputEl, fileId);\n });\n }\n\n // The name has been updated if the user presses enter.\n function registerInputEnterKeyHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"keyup\", function(event) {\n\n var code = event.keyCode || event.which;\n\n if (code === 13) {\n handleNameUpdate(inputEl, fileId);\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n\n qq.extend(inheritedInternalApi, {\n handleFilenameEdit: function(id, target, focusInput) {\n var newFilenameInputEl = spec.templating.getEditInput(id);\n\n spec.onEditingStatusChange(id, true);\n\n newFilenameInputEl.value = getFilenameSansExtension(id);\n\n if (focusInput) {\n newFilenameInputEl.focus();\n }\n\n registerInputBlurHandler(newFilenameInputEl, id);\n registerInputEnterKeyHandler(newFilenameInputEl, id);\n }\n });\n};\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n/**\n * CryptoJS core components.\n */\nqq.CryptoJS = (function (Math, undefined) {\n /**\n * CryptoJS namespace.\n */\n var C = {};\n\n /**\n * Library namespace.\n */\n var C_lib = C.lib = {};\n\n /**\n * Base object for prototypal inheritance.\n */\n var Base = C_lib.Base = (function () {\n function F() {}\n\n return {\n /**\n * Creates a new object that inherits from this object.\n *\n * @param {Object} overrides Properties to copy into the new object.\n *\n * @return {Object} The new object.\n *\n * @static\n *\n * @example\n *\n * var MyType = CryptoJS.lib.Base.extend({\n * field: 'value',\n *\n * method: function () {\n * }\n * });\n */\n extend: function (overrides) {\n // Spawn\n F.prototype = this;\n var subtype = new F();\n\n // Augment\n if (overrides) {\n subtype.mixIn(overrides);\n }\n\n // Create default initializer\n if (!subtype.hasOwnProperty('init')) {\n subtype.init = function () {\n subtype.$super.init.apply(this, arguments);\n };\n }\n\n // Initializer's prototype is the subtype object\n subtype.init.prototype = subtype;\n\n // Reference supertype\n subtype.$super = this;\n\n return subtype;\n },\n\n /**\n * Extends this object and runs the init method.\n * Arguments to create() will be passed to init().\n *\n * @return {Object} The new object.\n *\n * @static\n *\n * @example\n *\n * var instance = MyType.create();\n */\n create: function () {\n var instance = this.extend();\n instance.init.apply(instance, arguments);\n\n return instance;\n },\n\n /**\n * Initializes a newly created object.\n * Override this method to add some logic when your objects are created.\n *\n * @example\n *\n * var MyType = CryptoJS.lib.Base.extend({\n * init: function () {\n * // ...\n * }\n * });\n */\n init: function () {\n },\n\n /**\n * Copies properties into this object.\n *\n * @param {Object} properties The properties to mix in.\n *\n * @example\n *\n * MyType.mixIn({\n * field: 'value'\n * });\n */\n mixIn: function (properties) {\n for (var propertyName in properties) {\n if (properties.hasOwnProperty(propertyName)) {\n this[propertyName] = properties[propertyName];\n }\n }\n\n // IE won't copy toString using the loop above\n if (properties.hasOwnProperty('toString')) {\n this.toString = properties.toString;\n }\n },\n\n /**\n * Creates a copy of this object.\n *\n * @return {Object} The clone.\n *\n * @example\n *\n * var clone = instance.clone();\n */\n clone: function () {\n return this.init.prototype.extend(this);\n }\n };\n }());\n\n /**\n * An array of 32-bit words.\n *\n * @property {Array} words The array of 32-bit words.\n * @property {number} sigBytes The number of significant bytes in this word array.\n */\n var WordArray = C_lib.WordArray = Base.extend({\n /**\n * Initializes a newly created word array.\n *\n * @param {Array} words (Optional) An array of 32-bit words.\n * @param {number} sigBytes (Optional) The number of significant bytes in the words.\n *\n * @example\n *\n * var wordArray = CryptoJS.lib.WordArray.create();\n * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);\n * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);\n */\n init: function (words, sigBytes) {\n words = this.words = words || [];\n\n if (sigBytes != undefined) {\n this.sigBytes = sigBytes;\n } else {\n this.sigBytes = words.length * 4;\n }\n },\n\n /**\n * Converts this word array to a string.\n *\n * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex\n *\n * @return {string} The stringified word array.\n *\n * @example\n *\n * var string = wordArray + '';\n * var string = wordArray.toString();\n * var string = wordArray.toString(CryptoJS.enc.Utf8);\n */\n toString: function (encoder) {\n return (encoder || Hex).stringify(this);\n },\n\n /**\n * Concatenates a word array to this word array.\n *\n * @param {WordArray} wordArray The word array to append.\n *\n * @return {WordArray} This word array.\n *\n * @example\n *\n * wordArray1.concat(wordArray2);\n */\n concat: function (wordArray) {\n // Shortcuts\n var thisWords = this.words;\n var thatWords = wordArray.words;\n var thisSigBytes = this.sigBytes;\n var thatSigBytes = wordArray.sigBytes;\n\n // Clamp excess bits\n this.clamp();\n\n // Concat\n if (thisSigBytes % 4) {\n // Copy one byte at a time\n for (var i = 0; i < thatSigBytes; i++) {\n var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);\n }\n } else if (thatWords.length > 0xffff) {\n // Copy one word at a time\n for (var i = 0; i < thatSigBytes; i += 4) {\n thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];\n }\n } else {\n // Copy all words at once\n thisWords.push.apply(thisWords, thatWords);\n }\n this.sigBytes += thatSigBytes;\n\n // Chainable\n return this;\n },\n\n /**\n * Removes insignificant bits.\n *\n * @example\n *\n * wordArray.clamp();\n */\n clamp: function () {\n // Shortcuts\n var words = this.words;\n var sigBytes = this.sigBytes;\n\n // Clamp\n words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);\n words.length = Math.ceil(sigBytes / 4);\n },\n\n /**\n * Creates a copy of this word array.\n *\n * @return {WordArray} The clone.\n *\n * @example\n *\n * var clone = wordArray.clone();\n */\n clone: function () {\n var clone = Base.clone.call(this);\n clone.words = this.words.slice(0);\n\n return clone;\n },\n\n /**\n * Creates a word array filled with random bytes.\n *\n * @param {number} nBytes The number of random bytes to generate.\n *\n * @return {WordArray} The random word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.lib.WordArray.random(16);\n */\n random: function (nBytes) {\n var words = [];\n for (var i = 0; i < nBytes; i += 4) {\n words.push((Math.random() * 0x100000000) | 0);\n }\n\n return new WordArray.init(words, nBytes);\n }\n });\n\n /**\n * Encoder namespace.\n */\n var C_enc = C.enc = {};\n\n /**\n * Hex encoding strategy.\n */\n var Hex = C_enc.Hex = {\n /**\n * Converts a word array to a hex string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The hex string.\n *\n * @static\n *\n * @example\n *\n * var hexString = CryptoJS.enc.Hex.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n\n // Convert\n var hexChars = [];\n for (var i = 0; i < sigBytes; i++) {\n var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n hexChars.push((bite >>> 4).toString(16));\n hexChars.push((bite & 0x0f).toString(16));\n }\n\n return hexChars.join('');\n },\n\n /**\n * Converts a hex string to a word array.\n *\n * @param {string} hexStr The hex string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Hex.parse(hexString);\n */\n parse: function (hexStr) {\n // Shortcut\n var hexStrLength = hexStr.length;\n\n // Convert\n var words = [];\n for (var i = 0; i < hexStrLength; i += 2) {\n words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);\n }\n\n return new WordArray.init(words, hexStrLength / 2);\n }\n };\n\n /**\n * Latin1 encoding strategy.\n */\n var Latin1 = C_enc.Latin1 = {\n /**\n * Converts a word array to a Latin1 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Latin1 string.\n *\n * @static\n *\n * @example\n *\n * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n\n // Convert\n var latin1Chars = [];\n for (var i = 0; i < sigBytes; i++) {\n var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n latin1Chars.push(String.fromCharCode(bite));\n }\n\n return latin1Chars.join('');\n },\n\n /**\n * Converts a Latin1 string to a word array.\n *\n * @param {string} latin1Str The Latin1 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Latin1.parse(latin1String);\n */\n parse: function (latin1Str) {\n // Shortcut\n var latin1StrLength = latin1Str.length;\n\n // Convert\n var words = [];\n for (var i = 0; i < latin1StrLength; i++) {\n words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);\n }\n\n return new WordArray.init(words, latin1StrLength);\n }\n };\n\n /**\n * UTF-8 encoding strategy.\n */\n var Utf8 = C_enc.Utf8 = {\n /**\n * Converts a word array to a UTF-8 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The UTF-8 string.\n *\n * @static\n *\n * @example\n *\n * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);\n */\n stringify: function (wordArray) {\n try {\n return decodeURIComponent(escape(Latin1.stringify(wordArray)));\n } catch (e) {\n throw new Error('Malformed UTF-8 data');\n }\n },\n\n /**\n * Converts a UTF-8 string to a word array.\n *\n * @param {string} utf8Str The UTF-8 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Utf8.parse(utf8String);\n */\n parse: function (utf8Str) {\n return Latin1.parse(unescape(encodeURIComponent(utf8Str)));\n }\n };\n\n /**\n * Abstract buffered block algorithm template.\n *\n * The property blockSize must be implemented in a concrete subtype.\n *\n * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0\n */\n var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({\n /**\n * Resets this block algorithm's data buffer to its initial state.\n *\n * @example\n *\n * bufferedBlockAlgorithm.reset();\n */\n reset: function () {\n // Initial values\n this._data = new WordArray.init();\n this._nDataBytes = 0;\n },\n\n /**\n * Adds new data to this block algorithm's buffer.\n *\n * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.\n *\n * @example\n *\n * bufferedBlockAlgorithm._append('data');\n * bufferedBlockAlgorithm._append(wordArray);\n */\n _append: function (data) {\n // Convert string to WordArray, else assume WordArray already\n if (typeof data == 'string') {\n data = Utf8.parse(data);\n }\n\n // Append\n this._data.concat(data);\n this._nDataBytes += data.sigBytes;\n },\n\n /**\n * Processes available data blocks.\n *\n * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.\n *\n * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.\n *\n * @return {WordArray} The processed data.\n *\n * @example\n *\n * var processedData = bufferedBlockAlgorithm._process();\n * var processedData = bufferedBlockAlgorithm._process(!!'flush');\n */\n _process: function (doFlush) {\n // Shortcuts\n var data = this._data;\n var dataWords = data.words;\n var dataSigBytes = data.sigBytes;\n var blockSize = this.blockSize;\n var blockSizeBytes = blockSize * 4;\n\n // Count blocks ready\n var nBlocksReady = dataSigBytes / blockSizeBytes;\n if (doFlush) {\n // Round up to include partial blocks\n nBlocksReady = Math.ceil(nBlocksReady);\n } else {\n // Round down to include only full blocks,\n // less the number of blocks that must remain in the buffer\n nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);\n }\n\n // Count words ready\n var nWordsReady = nBlocksReady * blockSize;\n\n // Count bytes ready\n var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);\n\n // Process blocks\n if (nWordsReady) {\n for (var offset = 0; offset < nWordsReady; offset += blockSize) {\n // Perform concrete-algorithm logic\n this._doProcessBlock(dataWords, offset);\n }\n\n // Remove processed words\n var processedWords = dataWords.splice(0, nWordsReady);\n data.sigBytes -= nBytesReady;\n }\n\n // Return processed words\n return new WordArray.init(processedWords, nBytesReady);\n },\n\n /**\n * Creates a copy of this object.\n *\n * @return {Object} The clone.\n *\n * @example\n *\n * var clone = bufferedBlockAlgorithm.clone();\n */\n clone: function () {\n var clone = Base.clone.call(this);\n clone._data = this._data.clone();\n\n return clone;\n },\n\n _minBufferSize: 0\n });\n\n /**\n * Abstract hasher template.\n *\n * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)\n */\n var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({\n /**\n * Configuration options.\n */\n cfg: Base.extend(),\n\n /**\n * Initializes a newly created hasher.\n *\n * @param {Object} cfg (Optional) The configuration options to use for this hash computation.\n *\n * @example\n *\n * var hasher = CryptoJS.algo.SHA256.create();\n */\n init: function (cfg) {\n // Apply config defaults\n this.cfg = this.cfg.extend(cfg);\n\n // Set initial values\n this.reset();\n },\n\n /**\n * Resets this hasher to its initial state.\n *\n * @example\n *\n * hasher.reset();\n */\n reset: function () {\n // Reset data buffer\n BufferedBlockAlgorithm.reset.call(this);\n\n // Perform concrete-hasher logic\n this._doReset();\n },\n\n /**\n * Updates this hasher with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {Hasher} This hasher.\n *\n * @example\n *\n * hasher.update('message');\n * hasher.update(wordArray);\n */\n update: function (messageUpdate) {\n // Append\n this._append(messageUpdate);\n\n // Update the hash\n this._process();\n\n // Chainable\n return this;\n },\n\n /**\n * Finalizes the hash computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The hash.\n *\n * @example\n *\n * var hash = hasher.finalize();\n * var hash = hasher.finalize('message');\n * var hash = hasher.finalize(wordArray);\n */\n finalize: function (messageUpdate) {\n // Final message update\n if (messageUpdate) {\n this._append(messageUpdate);\n }\n\n // Perform concrete-hasher logic\n var hash = this._doFinalize();\n\n return hash;\n },\n\n blockSize: 512/32,\n\n /**\n * Creates a shortcut function to a hasher's object interface.\n *\n * @param {Hasher} hasher The hasher to create a helper for.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);\n */\n _createHelper: function (hasher) {\n return function (message, cfg) {\n return new hasher.init(cfg).finalize(message);\n };\n },\n\n /**\n * Creates a shortcut function to the HMAC's object interface.\n *\n * @param {Hasher} hasher The hasher to use in this HMAC helper.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);\n */\n _createHmacHelper: function (hasher) {\n return function (message, key) {\n return new C_algo.HMAC.init(hasher, key).finalize(message);\n };\n }\n });\n\n /**\n * Algorithm namespace.\n */\n var C_algo = C.algo = {};\n\n return C;\n}(Math));\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var WordArray = C_lib.WordArray;\n var C_enc = C.enc;\n\n /**\n * Base64 encoding strategy.\n */\n var Base64 = C_enc.Base64 = {\n /**\n * Converts a word array to a Base64 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Base64 string.\n *\n * @static\n *\n * @example\n *\n * var base64String = CryptoJS.enc.Base64.stringify(wordArray);\n */\n stringify: function (wordArray) {\n // Shortcuts\n var words = wordArray.words;\n var sigBytes = wordArray.sigBytes;\n var map = this._map;\n\n // Clamp excess bits\n wordArray.clamp();\n\n // Convert\n var base64Chars = [];\n for (var i = 0; i < sigBytes; i += 3) {\n var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;\n var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;\n\n var triplet = (byte1 << 16) | (byte2 << 8) | byte3;\n\n for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {\n base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));\n }\n }\n\n // Add padding\n var paddingChar = map.charAt(64);\n if (paddingChar) {\n while (base64Chars.length % 4) {\n base64Chars.push(paddingChar);\n }\n }\n\n return base64Chars.join('');\n },\n\n /**\n * Converts a Base64 string to a word array.\n *\n * @param {string} base64Str The Base64 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Base64.parse(base64String);\n */\n parse: function (base64Str) {\n // Shortcuts\n var base64StrLength = base64Str.length;\n var map = this._map;\n\n // Ignore padding\n var paddingChar = map.charAt(64);\n if (paddingChar) {\n var paddingIndex = base64Str.indexOf(paddingChar);\n if (paddingIndex != -1) {\n base64StrLength = paddingIndex;\n }\n }\n\n // Convert\n var words = [];\n var nBytes = 0;\n for (var i = 0; i < base64StrLength; i++) {\n if (i % 4) {\n var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2);\n var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2);\n words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8);\n nBytes++;\n }\n }\n\n return WordArray.create(words, nBytes);\n },\n\n _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='\n };\n}());\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var Base = C_lib.Base;\n var C_enc = C.enc;\n var Utf8 = C_enc.Utf8;\n var C_algo = C.algo;\n\n /**\n * HMAC algorithm.\n */\n var HMAC = C_algo.HMAC = Base.extend({\n /**\n * Initializes a newly created HMAC.\n *\n * @param {Hasher} hasher The hash algorithm to use.\n * @param {WordArray|string} key The secret key.\n *\n * @example\n *\n * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);\n */\n init: function (hasher, key) {\n // Init hasher\n hasher = this._hasher = new hasher.init();\n\n // Convert string to WordArray, else assume WordArray already\n if (typeof key == 'string') {\n key = Utf8.parse(key);\n }\n\n // Shortcuts\n var hasherBlockSize = hasher.blockSize;\n var hasherBlockSizeBytes = hasherBlockSize * 4;\n\n // Allow arbitrary length keys\n if (key.sigBytes > hasherBlockSizeBytes) {\n key = hasher.finalize(key);\n }\n\n // Clamp excess bits\n key.clamp();\n\n // Clone key for inner and outer pads\n var oKey = this._oKey = key.clone();\n var iKey = this._iKey = key.clone();\n\n // Shortcuts\n var oKeyWords = oKey.words;\n var iKeyWords = iKey.words;\n\n // XOR keys with pad constants\n for (var i = 0; i < hasherBlockSize; i++) {\n oKeyWords[i] ^= 0x5c5c5c5c;\n iKeyWords[i] ^= 0x36363636;\n }\n oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;\n\n // Set initial values\n this.reset();\n },\n\n /**\n * Resets this HMAC to its initial state.\n *\n * @example\n *\n * hmacHasher.reset();\n */\n reset: function () {\n // Shortcut\n var hasher = this._hasher;\n\n // Reset\n hasher.reset();\n hasher.update(this._iKey);\n },\n\n /**\n * Updates this HMAC with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {HMAC} This HMAC instance.\n *\n * @example\n *\n * hmacHasher.update('message');\n * hmacHasher.update(wordArray);\n */\n update: function (messageUpdate) {\n this._hasher.update(messageUpdate);\n\n // Chainable\n return this;\n },\n\n /**\n * Finalizes the HMAC computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The HMAC.\n *\n * @example\n *\n * var hmac = hmacHasher.finalize();\n * var hmac = hmacHasher.finalize('message');\n * var hmac = hmacHasher.finalize(wordArray);\n */\n finalize: function (messageUpdate) {\n // Shortcut\n var hasher = this._hasher;\n\n // Compute HMAC\n var innerHash = hasher.finalize(messageUpdate);\n hasher.reset();\n var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));\n\n return hmac;\n }\n });\n}());\n","/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto-js/wiki/License\n*/\n(function () {\n // Shortcuts\n var C = qq.CryptoJS;\n var C_lib = C.lib;\n var WordArray = C_lib.WordArray;\n var Hasher = C_lib.Hasher;\n var C_algo = C.algo;\n\n // Reusable object\n var W = [];\n\n /**\n * SHA-1 hash algorithm.\n */\n var SHA1 = C_algo.SHA1 = Hasher.extend({\n _doReset: function () {\n this._hash = new WordArray.init([\n 0x67452301, 0xefcdab89,\n 0x98badcfe, 0x10325476,\n 0xc3d2e1f0\n ]);\n },\n\n _doProcessBlock: function (M, offset) {\n // Shortcut\n var H = this._hash.words;\n\n // Working variables\n var a = H[0];\n var b = H[1];\n var c = H[2];\n var d = H[3];\n var e = H[4];\n\n // Computation\n for (var i = 0; i < 80; i++) {\n if (i < 16) {\n W[i] = M[offset + i] | 0;\n } else {\n var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];\n W[i] = (n << 1) | (n >>> 31);\n }\n\n var t = ((a << 5) | (a >>> 27)) + e + W[i];\n if (i < 20) {\n t += ((b & c) | (~b & d)) + 0x5a827999;\n } else if (i < 40) {\n t += (b ^ c ^ d) + 0x6ed9eba1;\n } else if (i < 60) {\n t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;\n } else /* if (i < 80) */ {\n t += (b ^ c ^ d) - 0x359d3e2a;\n }\n\n e = d;\n d = c;\n c = (b << 30) | (b >>> 2);\n b = a;\n a = t;\n }\n\n // Intermediate hash value\n H[0] = (H[0] + a) | 0;\n H[1] = (H[1] + b) | 0;\n H[2] = (H[2] + c) | 0;\n H[3] = (H[3] + d) | 0;\n H[4] = (H[4] + e) | 0;\n },\n\n _doFinalize: function () {\n // Shortcuts\n var data = this._data;\n var dataWords = data.words;\n\n var nBitsTotal = this._nDataBytes * 8;\n var nBitsLeft = data.sigBytes * 8;\n\n // Add padding\n dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\n data.sigBytes = dataWords.length * 4;\n\n // Hash final blocks\n this._process();\n\n // Return final computed hash\n return this._hash;\n },\n\n clone: function () {\n var clone = Hasher.clone.call(this);\n clone._hash = this._hash.clone();\n\n return clone;\n }\n });\n\n /**\n * Shortcut function to the hasher's object interface.\n *\n * @param {WordArray|string} message The message to hash.\n *\n * @return {WordArray} The hash.\n *\n * @static\n *\n * @example\n *\n * var hash = CryptoJS.SHA1('message');\n * var hash = CryptoJS.SHA1(wordArray);\n */\n C.SHA1 = Hasher._createHelper(SHA1);\n\n /**\n * Shortcut function to the HMAC's object interface.\n *\n * @param {WordArray|string} message The message to hash.\n * @param {WordArray|string} key The secret key.\n *\n * @return {WordArray} The HMAC.\n *\n * @static\n *\n * @example\n *\n * var hmac = CryptoJS.HmacSHA1(message, key);\n */\n C.HmacSHA1 = Hasher._createHmacHelper(SHA1);\n}());\n","/*\r\nCryptoJS v3.1.2\r\ncode.google.com/p/crypto-js\r\n(c) 2009-2013 by Jeff Mott. All rights reserved.\r\ncode.google.com/p/crypto-js/wiki/License\r\n*/\r\n(function (Math) {\r\n // Shortcuts\r\n var C = qq.CryptoJS;\r\n var C_lib = C.lib;\r\n var WordArray = C_lib.WordArray;\r\n var Hasher = C_lib.Hasher;\r\n var C_algo = C.algo;\r\n\r\n // Initialization and round constants tables\r\n var H = [];\r\n var K = [];\r\n\r\n // Compute constants\r\n (function () {\r\n function isPrime(n) {\r\n var sqrtN = Math.sqrt(n);\r\n for (var factor = 2; factor <= sqrtN; factor++) {\r\n if (!(n % factor)) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n function getFractionalBits(n) {\r\n return ((n - (n | 0)) * 0x100000000) | 0;\r\n }\r\n\r\n var n = 2;\r\n var nPrime = 0;\r\n while (nPrime < 64) {\r\n if (isPrime(n)) {\r\n if (nPrime < 8) {\r\n H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));\r\n }\r\n K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));\r\n\r\n nPrime++;\r\n }\r\n\r\n n++;\r\n }\r\n }());\r\n\r\n // Reusable object\r\n var W = [];\r\n\r\n /**\r\n * SHA-256 hash algorithm.\r\n */\r\n var SHA256 = C_algo.SHA256 = Hasher.extend({\r\n _doReset: function () {\r\n this._hash = new WordArray.init(H.slice(0));\r\n },\r\n\r\n _doProcessBlock: function (M, offset) {\r\n // Shortcut\r\n var H = this._hash.words;\r\n\r\n // Working variables\r\n var a = H[0];\r\n var b = H[1];\r\n var c = H[2];\r\n var d = H[3];\r\n var e = H[4];\r\n var f = H[5];\r\n var g = H[6];\r\n var h = H[7];\r\n\r\n // Computation\r\n for (var i = 0; i < 64; i++) {\r\n if (i < 16) {\r\n W[i] = M[offset + i] | 0;\r\n } else {\r\n var gamma0x = W[i - 15];\r\n var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^\r\n ((gamma0x << 14) | (gamma0x >>> 18)) ^\r\n (gamma0x >>> 3);\r\n\r\n var gamma1x = W[i - 2];\r\n var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^\r\n ((gamma1x << 13) | (gamma1x >>> 19)) ^\r\n (gamma1x >>> 10);\r\n\r\n W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];\r\n }\r\n\r\n var ch = (e & f) ^ (~e & g);\r\n var maj = (a & b) ^ (a & c) ^ (b & c);\r\n\r\n var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));\r\n var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25));\r\n\r\n var t1 = h + sigma1 + ch + K[i] + W[i];\r\n var t2 = sigma0 + maj;\r\n\r\n h = g;\r\n g = f;\r\n f = e;\r\n e = (d + t1) | 0;\r\n d = c;\r\n c = b;\r\n b = a;\r\n a = (t1 + t2) | 0;\r\n }\r\n\r\n // Intermediate hash value\r\n H[0] = (H[0] + a) | 0;\r\n H[1] = (H[1] + b) | 0;\r\n H[2] = (H[2] + c) | 0;\r\n H[3] = (H[3] + d) | 0;\r\n H[4] = (H[4] + e) | 0;\r\n H[5] = (H[5] + f) | 0;\r\n H[6] = (H[6] + g) | 0;\r\n H[7] = (H[7] + h) | 0;\r\n },\r\n\r\n _doFinalize: function () {\r\n // Shortcuts\r\n var data = this._data;\r\n var dataWords = data.words;\r\n\r\n var nBitsTotal = this._nDataBytes * 8;\r\n var nBitsLeft = data.sigBytes * 8;\r\n\r\n // Add padding\r\n dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\r\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\r\n dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\r\n data.sigBytes = dataWords.length * 4;\r\n\r\n // Hash final blocks\r\n this._process();\r\n\r\n // Return final computed hash\r\n return this._hash;\r\n },\r\n\r\n clone: function () {\r\n var clone = Hasher.clone.call(this);\r\n clone._hash = this._hash.clone();\r\n\r\n return clone;\r\n }\r\n });\r\n\r\n /**\r\n * Shortcut function to the hasher's object interface.\r\n *\r\n * @param {WordArray|string} message The message to hash.\r\n *\r\n * @return {WordArray} The hash.\r\n *\r\n * @static\r\n *\r\n * @example\r\n *\r\n * var hash = CryptoJS.SHA256('message');\r\n * var hash = CryptoJS.SHA256(wordArray);\r\n */\r\n C.SHA256 = Hasher._createHelper(SHA256);\r\n\r\n /**\r\n * Shortcut function to the HMAC's object interface.\r\n *\r\n * @param {WordArray|string} message The message to hash.\r\n * @param {WordArray|string} key The secret key.\r\n *\r\n * @return {WordArray} The HMAC.\r\n *\r\n * @static\r\n *\r\n * @example\r\n *\r\n * var hmac = CryptoJS.HmacSHA256(message, key);\r\n */\r\n C.HmacSHA256 = Hasher._createHmacHelper(SHA256);\r\n}(Math));\r\n","/*\r\nCryptoJS v3.1.2\r\ncode.google.com/p/crypto-js\r\n(c) 2009-2013 by Jeff Mott. All rights reserved.\r\ncode.google.com/p/crypto-js/wiki/License\r\n*/\r\n(function () {\r\n // Check if typed arrays are supported\r\n if (typeof ArrayBuffer != 'function') {\r\n return;\r\n }\r\n\r\n // Shortcuts\r\n var C = qq.CryptoJS;\r\n var C_lib = C.lib;\r\n var WordArray = C_lib.WordArray;\r\n\r\n // Reference original init\r\n var superInit = WordArray.init;\r\n\r\n // Augment WordArray.init to handle typed arrays\r\n var subInit = WordArray.init = function (typedArray) {\r\n // Convert buffers to uint8\r\n if (typedArray instanceof ArrayBuffer) {\r\n typedArray = new Uint8Array(typedArray);\r\n }\r\n\r\n // Convert other array views to uint8\r\n if (\r\n typedArray instanceof Int8Array ||\r\n typedArray instanceof Uint8ClampedArray ||\r\n typedArray instanceof Int16Array ||\r\n typedArray instanceof Uint16Array ||\r\n typedArray instanceof Int32Array ||\r\n typedArray instanceof Uint32Array ||\r\n typedArray instanceof Float32Array ||\r\n typedArray instanceof Float64Array\r\n ) {\r\n typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);\r\n }\r\n\r\n // Handle Uint8Array\r\n if (typedArray instanceof Uint8Array) {\r\n // Shortcut\r\n var typedArrayByteLength = typedArray.byteLength;\r\n\r\n // Extract bytes\r\n var words = [];\r\n for (var i = 0; i < typedArrayByteLength; i++) {\r\n words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8);\r\n }\r\n\r\n // Initialize this word array\r\n superInit.call(this, words, typedArrayByteLength);\r\n } else {\r\n // Else call normal init\r\n superInit.apply(this, arguments);\r\n }\r\n };\r\n\r\n subInit.prototype = WordArray;\r\n}());\r\n","/*globals qq */\nqq.s3 = qq.s3 || {};\n\nqq.s3.util = qq.s3.util || (function() {\n \"use strict\";\n\n return {\n ALGORITHM_PARAM_NAME: \"x-amz-algorithm\",\n\n AWS_PARAM_PREFIX: \"x-amz-meta-\",\n\n CREDENTIAL_PARAM_NAME: \"x-amz-credential\",\n\n DATE_PARAM_NAME: \"x-amz-date\",\n\n REDUCED_REDUNDANCY_PARAM_NAME: \"x-amz-storage-class\",\n REDUCED_REDUNDANCY_PARAM_VALUE: \"REDUCED_REDUNDANCY\",\n\n SERVER_SIDE_ENCRYPTION_PARAM_NAME: \"x-amz-server-side-encryption\",\n SERVER_SIDE_ENCRYPTION_PARAM_VALUE: \"AES256\",\n\n SESSION_TOKEN_PARAM_NAME: \"x-amz-security-token\",\n\n V4_ALGORITHM_PARAM_VALUE: \"AWS4-HMAC-SHA256\",\n\n V4_SIGNATURE_PARAM_NAME: \"x-amz-signature\",\n\n CASE_SENSITIVE_PARAM_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\"\n ],\n\n UNSIGNABLE_REST_HEADER_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\"\n ],\n\n UNPREFIXED_PARAM_NAMES: [\n \"Cache-Control\",\n \"Content-Disposition\",\n \"Content-Encoding\",\n \"Content-MD5\",\n \"x-amz-server-side-encryption-customer-algorithm\",\n \"x-amz-server-side-encryption-customer-key\",\n \"x-amz-server-side-encryption-customer-key-MD5\"\n ],\n\n /**\n * This allows for the region to be specified in the bucket's endpoint URL, or not.\n *\n * Examples of some valid endpoints are:\n * http://foo.s3.amazonaws.com\n * https://foo.s3.amazonaws.com\n * http://foo.s3-ap-northeast-1.amazonaws.com\n * foo.s3.amazonaws.com\n * http://foo.bar.com\n * http://s3.amazonaws.com/foo.bar.com\n * ...etc\n *\n * @param endpoint The bucket's URL.\n * @returns {String || undefined} The bucket name, or undefined if the URL cannot be parsed.\n */\n getBucket: function(endpoint) {\n var patterns = [\n //bucket in domain\n /^(?:https?:\\/\\/)?([a-z0-9.\\-_]+)\\.s3(?:-[a-z0-9\\-]+)?\\.amazonaws\\.com/i,\n //bucket in path\n /^(?:https?:\\/\\/)?s3(?:-[a-z0-9\\-]+)?\\.amazonaws\\.com\\/([a-z0-9.\\-_]+)/i,\n //custom domain\n /^(?:https?:\\/\\/)?([a-z0-9.\\-_]+)/i\n ],\n bucket;\n\n qq.each(patterns, function(idx, pattern) {\n var match = pattern.exec(endpoint);\n\n if (match) {\n bucket = match[1];\n return false;\n }\n });\n\n return bucket;\n },\n\n /** Create Prefixed request headers which are appropriate for S3.\n *\n * If the request header is appropriate for S3 (e.g. Cache-Control) then pass\n * it along without a metadata prefix. For all other request header parameter names,\n * apply qq.s3.util.AWS_PARAM_PREFIX before the name.\n * See: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html\n */\n _getPrefixedParamName: function(name) {\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {\n return name;\n }\n return qq.s3.util.AWS_PARAM_PREFIX + name;\n },\n\n /**\n * Create a policy document to be signed and sent along with the S3 upload request.\n *\n * @param spec Object with properties use to construct the policy document.\n * @returns {Object} Policy doc.\n */\n getPolicy: function(spec) {\n var policy = {},\n conditions = [],\n bucket = spec.bucket,\n date = spec.date,\n drift = spec.clockDrift,\n key = spec.key,\n accessKey = spec.accessKey,\n acl = spec.acl,\n type = spec.type,\n expectedStatus = spec.expectedStatus,\n sessionToken = spec.sessionToken,\n params = spec.params,\n successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl),\n minFileSize = spec.minFileSize,\n maxFileSize = spec.maxFileSize,\n reducedRedundancy = spec.reducedRedundancy,\n region = spec.region,\n serverSideEncryption = spec.serverSideEncryption,\n signatureVersion = spec.signatureVersion;\n\n policy.expiration = qq.s3.util.getPolicyExpirationDate(date, drift);\n\n conditions.push({acl: acl});\n conditions.push({bucket: bucket});\n\n if (type) {\n conditions.push({\"Content-Type\": type});\n }\n\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (expectedStatus) {\n conditions.push({success_action_status: expectedStatus.toString()});\n }\n\n if (successRedirectUrl) {\n conditions.push({success_action_redirect: successRedirectUrl});\n }\n // jscs:enable\n if (reducedRedundancy) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (sessionToken) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n if (serverSideEncryption) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n if (signatureVersion === 2) {\n conditions.push({key: key});\n }\n else if (signatureVersion === 4) {\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;\n\n conditions.push({});\n conditions[conditions.length - 1].key = key;\n\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.CREDENTIAL_PARAM_NAME] =\n qq.s3.util.getV4CredentialsString({date: date, key: accessKey, region: region});\n\n conditions.push({});\n conditions[conditions.length - 1][qq.s3.util.DATE_PARAM_NAME] =\n qq.s3.util.getV4PolicyDate(date, drift);\n }\n\n // user metadata\n qq.each(params, function(name, val) {\n var awsParamName = qq.s3.util._getPrefixedParamName(name),\n param = {};\n\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {\n param[awsParamName] = val;\n }\n else {\n param[awsParamName] = encodeURIComponent(val);\n }\n\n conditions.push(param);\n });\n\n policy.conditions = conditions;\n\n qq.s3.util.enforceSizeLimits(policy, minFileSize, maxFileSize);\n\n return policy;\n },\n\n /**\n * Update a previously constructed policy document with updated credentials. Currently, this only requires we\n * update the session token. This is only relevant if requests are being signed client-side.\n *\n * @param policy Live policy document\n * @param newSessionToken Updated session token.\n */\n refreshPolicyCredentials: function(policy, newSessionToken) {\n var sessionTokenFound = false;\n\n qq.each(policy.conditions, function(oldCondIdx, oldCondObj) {\n qq.each(oldCondObj, function(oldCondName, oldCondVal) {\n if (oldCondName === qq.s3.util.SESSION_TOKEN_PARAM_NAME) {\n oldCondObj[oldCondName] = newSessionToken;\n sessionTokenFound = true;\n }\n });\n });\n\n if (!sessionTokenFound) {\n policy.conditions.push({});\n policy.conditions[policy.conditions.length - 1][qq.s3.util.SESSION_TOKEN_PARAM_NAME] = newSessionToken;\n }\n },\n\n /**\n * Generates all parameters to be passed along with the S3 upload request. This includes invoking a callback\n * that is expected to asynchronously retrieve a signature for the policy document. Note that the server\n * signing the request should reject a \"tainted\" policy document that includes unexpected values, since it is\n * still possible for a malicious user to tamper with these values during policy document generation,\n * before it is sent to the server for signing.\n *\n * @param spec Object with properties: `params`, `type`, `key`, `accessKey`, `acl`, `expectedStatus`, `successRedirectUrl`,\n * `reducedRedundancy`, `region`, `serverSideEncryption`, `version`, and `log()`, along with any options associated with `qq.s3.util.getPolicy()`.\n * @returns {qq.Promise} Promise that will be fulfilled once all parameters have been determined.\n */\n generateAwsParams: function(spec, signPolicyCallback) {\n var awsParams = {},\n customParams = spec.params,\n promise = new qq.Promise(),\n sessionToken = spec.sessionToken,\n drift = spec.clockDrift,\n type = spec.type,\n key = spec.key,\n accessKey = spec.accessKey,\n acl = spec.acl,\n expectedStatus = spec.expectedStatus,\n successRedirectUrl = qq.s3.util.getSuccessRedirectAbsoluteUrl(spec.successRedirectUrl),\n reducedRedundancy = spec.reducedRedundancy,\n region = spec.region,\n serverSideEncryption = spec.serverSideEncryption,\n signatureVersion = spec.signatureVersion,\n now = new Date(),\n log = spec.log,\n policyJson;\n\n spec.date = now;\n policyJson = qq.s3.util.getPolicy(spec);\n\n awsParams.key = key;\n\n if (type) {\n awsParams[\"Content-Type\"] = type;\n }\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (expectedStatus) {\n awsParams.success_action_status = expectedStatus;\n }\n\n if (successRedirectUrl) {\n awsParams.success_action_redirect = successRedirectUrl;\n }\n // jscs:enable\n if (reducedRedundancy) {\n awsParams[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (serverSideEncryption) {\n awsParams[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n if (sessionToken) {\n awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n awsParams.acl = acl;\n\n // Custom (user-supplied) params must be prefixed with the value of `qq.s3.util.AWS_PARAM_PREFIX`.\n // Params such as Cache-Control or Content-Disposition will not be prefixed.\n // Prefixed param values will be URI encoded as well.\n qq.each(customParams, function(name, val) {\n var awsParamName = qq.s3.util._getPrefixedParamName(name);\n\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, awsParamName) >= 0) {\n awsParams[awsParamName] = val;\n }\n else {\n awsParams[awsParamName] = encodeURIComponent(val);\n }\n });\n\n if (signatureVersion === 2) {\n awsParams.AWSAccessKeyId = accessKey;\n }\n else if (signatureVersion === 4) {\n awsParams[qq.s3.util.ALGORITHM_PARAM_NAME] = qq.s3.util.V4_ALGORITHM_PARAM_VALUE;\n awsParams[qq.s3.util.CREDENTIAL_PARAM_NAME] = qq.s3.util.getV4CredentialsString({date: now, key: accessKey, region: region});\n awsParams[qq.s3.util.DATE_PARAM_NAME] = qq.s3.util.getV4PolicyDate(now, drift);\n }\n\n // Invoke a promissory callback that should provide us with a base64-encoded policy doc and an\n // HMAC signature for the policy doc.\n signPolicyCallback(policyJson).then(\n function(policyAndSignature, updatedAccessKey, updatedSessionToken) {\n awsParams.policy = policyAndSignature.policy;\n\n if (spec.signatureVersion === 2) {\n awsParams.signature = policyAndSignature.signature;\n\n if (updatedAccessKey) {\n awsParams.AWSAccessKeyId = updatedAccessKey;\n }\n }\n else if (spec.signatureVersion === 4) {\n awsParams[qq.s3.util.V4_SIGNATURE_PARAM_NAME] = policyAndSignature.signature;\n }\n\n if (updatedSessionToken) {\n awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;\n }\n\n promise.success(awsParams);\n },\n function(errorMessage) {\n errorMessage = errorMessage || \"Can't continue further with request to S3 as we did not receive \" +\n \"a valid signature and policy from the server.\";\n\n log(\"Policy signing failed. \" + errorMessage, \"error\");\n promise.failure(errorMessage);\n }\n );\n\n return promise;\n },\n\n /**\n * Add a condition to an existing S3 upload request policy document used to ensure AWS enforces any size\n * restrictions placed on files server-side. This is important to do, in case users mess with the client-side\n * checks already in place.\n *\n * @param policy Policy document as an `Object`, with a `conditions` property already attached\n * @param minSize Minimum acceptable size, in bytes\n * @param maxSize Maximum acceptable size, in bytes (0 = unlimited)\n */\n enforceSizeLimits: function(policy, minSize, maxSize) {\n var adjustedMinSize = minSize < 0 ? 0 : minSize,\n // Adjust a maxSize of 0 to the largest possible integer, since we must specify a high and a low in the request\n adjustedMaxSize = maxSize <= 0 ? 9007199254740992 : maxSize;\n\n if (minSize > 0 || maxSize > 0) {\n policy.conditions.push([\"content-length-range\", adjustedMinSize.toString(), adjustedMaxSize.toString()]);\n }\n },\n\n getPolicyExpirationDate: function(date, drift) {\n var adjustedDate = new Date(date.getTime() + drift);\n return qq.s3.util.getPolicyDate(adjustedDate, 5);\n },\n\n getCredentialsDate: function(date) {\n return date.getUTCFullYear() + \"\" +\n (\"0\" + (date.getUTCMonth() + 1)).slice(-2) +\n (\"0\" + date.getUTCDate()).slice(-2);\n },\n\n getPolicyDate: function(date, _minutesToAdd_) {\n var minutesToAdd = _minutesToAdd_ || 0,\n pad, r;\n\n /*jshint -W014 */\n // Is this going to be a problem if we encounter this moments before 2 AM just before daylight savings time ends?\n date.setMinutes(date.getMinutes() + (minutesToAdd || 0));\n\n if (Date.prototype.toISOString) {\n return date.toISOString();\n }\n else {\n pad = function(number) {\n r = String(number);\n\n if (r.length === 1) {\n r = \"0\" + r;\n }\n\n return r;\n };\n\n return date.getUTCFullYear()\n + \"-\" + pad(date.getUTCMonth() + 1)\n + \"-\" + pad(date.getUTCDate())\n + \"T\" + pad(date.getUTCHours())\n + \":\" + pad(date.getUTCMinutes())\n + \":\" + pad(date.getUTCSeconds())\n + \".\" + String((date.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)\n + \"Z\";\n }\n },\n\n /**\n * Looks at a response from S3 contained in an iframe and parses the query string in an attempt to identify\n * the associated resource.\n *\n * @param iframe Iframe containing response\n * @returns {{bucket: *, key: *, etag: *}}\n */\n parseIframeResponse: function(iframe) {\n var doc = iframe.contentDocument || iframe.contentWindow.document,\n queryString = doc.location.search,\n match = /bucket=(.+)&key=(.+)&etag=(.+)/.exec(queryString);\n\n if (match) {\n return {\n bucket: match[1],\n key: match[2],\n etag: match[3].replace(/%22/g, \"\")\n };\n }\n },\n\n /**\n * @param successRedirectUrl Relative or absolute location of success redirect page\n * @returns {*|string} undefined if the parameter is undefined, otherwise the absolute location of the success redirect page\n */\n getSuccessRedirectAbsoluteUrl: function(successRedirectUrl) {\n if (successRedirectUrl) {\n var targetAnchorContainer = document.createElement(\"div\"),\n targetAnchor;\n\n if (qq.ie7()) {\n // Note that we must make use of `innerHTML` for IE7 only instead of simply creating an anchor via\n // `document.createElement('a')` and setting the `href` attribute. The latter approach does not allow us to\n // obtain an absolute URL in IE7 if the `endpoint` is a relative URL.\n targetAnchorContainer.innerHTML = \" \";\n targetAnchor = targetAnchorContainer.firstChild;\n return targetAnchor.href;\n }\n else {\n // IE8 and IE9 do not seem to derive an absolute URL from a relative URL using the `innerHTML`\n // approach above, so we'll just create an anchor this way and set it's `href` attribute.\n // Due to yet another quirk in IE8 and IE9, we have to set the `href` equal to itself\n // in order to ensure relative URLs will be properly parsed.\n targetAnchor = document.createElement(\"a\");\n targetAnchor.href = successRedirectUrl;\n targetAnchor.href = targetAnchor.href;\n return targetAnchor.href;\n }\n }\n },\n\n getV4CredentialsString: function(spec) {\n return spec.key + \"/\" +\n qq.s3.util.getCredentialsDate(spec.date) + \"/\" +\n spec.region + \"/s3/aws4_request\";\n },\n\n getV4PolicyDate: function(date, drift) {\n var adjustedDate = new Date(date.getTime() + drift);\n\n return qq.s3.util.getCredentialsDate(adjustedDate) + \"T\" +\n (\"0\" + adjustedDate.getUTCHours()).slice(-2) +\n (\"0\" + adjustedDate.getUTCMinutes()).slice(-2) +\n (\"0\" + adjustedDate.getUTCSeconds()).slice(-2) +\n \"Z\";\n },\n\n // AWS employs a strict interpretation of [RFC 3986](http://tools.ietf.org/html/rfc3986#page-12).\n // So, we must ensure all reserved characters listed in the spec are percent-encoded,\n // and spaces are replaced with \"+\".\n encodeQueryStringParam: function(param) {\n var percentEncoded = encodeURIComponent(param);\n\n // %-encode characters not handled by `encodeURIComponent` (to follow RFC 3986)\n percentEncoded = percentEncoded.replace(/[!'()]/g, escape);\n\n // %-encode characters not handled by `escape` (to follow RFC 3986)\n percentEncoded = percentEncoded.replace(/\\*/g, \"%2A\");\n\n // replace percent-encoded spaces with a \"+\"\n return percentEncoded.replace(/%20/g, \"+\");\n },\n /**\n * Escapes url part as for AWS requirements\n * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js\n */\n uriEscape: function(string) {\n var output = encodeURIComponent(string);\n output = output.replace(/[^A-Za-z0-9_.~\\-%]+/g, escape);\n output = output.replace(/[*]/g, function(ch) {\n return \"%\" + ch.charCodeAt(0).toString(16).toUpperCase();\n });\n return output;\n },\n /**\n * Escapes a path as for AWS requirement\n * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js\n */\n uriEscapePath: function(path) {\n var parts = [];\n qq.each(path.split(\"/\"), function(idx, item) {\n parts.push(qq.s3.util.uriEscape(item));\n });\n return parts.join(\"/\");\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to S3, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to S3.\n * Some inherited options and API methods have a special meaning in the context of the S3 uploader.\n */\n(function() {\n \"use strict\";\n\n qq.s3.FineUploaderBasic = function(o) {\n var options = {\n request: {\n // public key (required for server-side signing, ignored if `credentials` have been provided)\n accessKey: null,\n\n // padding, in milliseconds, to add to the x-amz-date header & the policy expiration date\n clockDrift: 0\n },\n\n objectProperties: {\n acl: \"private\",\n\n // string or a function which may be promissory\n bucket: qq.bind(function(id) {\n return qq.s3.util.getBucket(this.getEndpoint(id));\n }, this),\n\n // string or a function which may be promissory - only used for V4 multipart uploads\n host: qq.bind(function(id) {\n return (/(?:http|https):\\/\\/(.+)(?:\\/.+)?/).exec(this._endpointStore.get(id))[1];\n }, this),\n\n // 'uuid', 'filename', or a function which may be promissory\n key: \"uuid\",\n\n reducedRedundancy: false,\n\n // Defined at http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\n region: \"us-east-1\",\n\n serverSideEncryption: false\n },\n\n credentials: {\n // Public key (required).\n accessKey: null,\n // Private key (required).\n secretKey: null,\n // Expiration date for the credentials (required). May be an ISO string or a `Date`.\n expiration: null,\n // Temporary credentials session token.\n // Only required for temporary credentials obtained via AssumeRoleWithWebIdentity.\n sessionToken: null\n },\n\n // All but `version` are ignored if `credentials` is provided.\n signature: {\n customHeaders: {},\n endpoint: null,\n version: 2\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n // required if non-File-API browsers, such as IE9 and older, are used\n iframeSupport: {\n localBlankPagePath: null\n },\n\n chunking: {\n // minimum part size is 5 MiB when uploading to S3\n partSize: 5242880\n },\n\n cors: {\n allowXdr: true\n },\n\n callbacks: {\n onCredentialsExpired: function() {}\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n if (!this.setCredentials(options.credentials, true)) {\n this._currentCredentials.accessKey = options.request.accessKey;\n }\n\n this._aclStore = this._createStore(options.objectProperties.acl);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds S3 keys for file representations constructed from a session request.\n this._cannedKeys = {};\n // Holds S3 buckets for file representations constructed from a session request.\n this._cannedBuckets = {};\n\n this._buckets = {};\n this._hosts = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.s3.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.s3.FineUploaderBasic.prototype, {\n getBucket: function(id) {\n if (this._cannedBuckets[id] == null) {\n return this._buckets[id];\n }\n return this._cannedBuckets[id];\n },\n\n /**\n * @param id File ID\n * @returns {*} Key name associated w/ the file, if one exists\n */\n getKey: function(id) {\n /* jshint eqnull:true */\n if (this._cannedKeys[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n\n return this._cannedKeys[id];\n },\n\n /**\n * Override the parent's reset function to cleanup various S3-related items.\n */\n reset: function() {\n qq.FineUploaderBasic.prototype.reset.call(this);\n this._failedSuccessRequestCallbacks = [];\n this._buckets = {};\n this._hosts = {};\n },\n\n setCredentials: function(credentials, ignoreEmpty) {\n if (credentials && credentials.secretKey) {\n if (!credentials.accessKey) {\n throw new qq.Error(\"Invalid credentials: no accessKey\");\n }\n else if (!credentials.expiration) {\n throw new qq.Error(\"Invalid credentials: no expiration\");\n }\n else {\n this._currentCredentials = qq.extend({}, credentials);\n\n // Ensure expiration is a `Date`. If initially a string, assuming it is in ISO format.\n if (qq.isString(credentials.expiration)) {\n this._currentCredentials.expiration = new Date(credentials.expiration);\n }\n }\n\n return true;\n }\n else if (!ignoreEmpty) {\n throw new qq.Error(\"Invalid credentials parameter!\");\n }\n else {\n this._currentCredentials = {};\n }\n },\n\n setAcl: function(acl, id) {\n this._aclStore.set(acl, id);\n },\n\n /**\n * Ensures the parent's upload handler creator passes any additional S3-specific options to the handler as well\n * as information required to instantiate the specific handler based on the current browser's capabilities.\n *\n * @returns {qq.UploadHandlerController}\n * @private\n */\n _createUploadHandler: function() {\n var self = this,\n additionalOptions = {\n aclStore: this._aclStore,\n getBucket: qq.bind(this._determineBucket, this),\n getHost: qq.bind(this._determineHost, this),\n getKeyName: qq.bind(this._determineKeyName, this),\n iframeSupport: this._options.iframeSupport,\n objectProperties: this._options.objectProperties,\n signature: this._options.signature,\n clockDrift: this._options.request.clockDrift,\n // pass size limit validation values to include in the request so AWS enforces this server-side\n validation: {\n minSizeLimit: this._options.validation.minSizeLimit,\n maxSizeLimit: this._options.validation.sizeLimit\n }\n };\n\n // We assume HTTP if it is missing from the start of the endpoint string.\n qq.override(this._endpointStore, function(super_) {\n return {\n get: function(id) {\n var endpoint = super_.get(id);\n\n if (endpoint.indexOf(\"http\") < 0) {\n return \"http://\" + endpoint;\n }\n\n return endpoint;\n }\n };\n });\n\n // Some param names should be lower case to avoid signature mismatches\n qq.override(this._paramsStore, function(super_) {\n return {\n get: function(id) {\n var oldParams = super_.get(id),\n modifiedParams = {};\n\n qq.each(oldParams, function(name, val) {\n var paramName = name;\n\n if (qq.indexOf(qq.s3.util.CASE_SENSITIVE_PARAM_NAMES, paramName) < 0) {\n paramName = paramName.toLowerCase();\n }\n\n modifiedParams[paramName] = qq.isFunction(val) ? val() : val;\n });\n\n return modifiedParams;\n }\n };\n });\n\n additionalOptions.signature.credentialsProvider = {\n get: function() {\n return self._currentCredentials;\n },\n\n onExpired: function() {\n var updateCredentials = new qq.Promise(),\n callbackRetVal = self._options.callbacks.onCredentialsExpired();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n callbackRetVal.then(function(credentials) {\n try {\n self.setCredentials(credentials);\n updateCredentials.success();\n }\n catch (error) {\n self.log(\"Invalid credentials returned from onCredentialsExpired callback! (\" + error.message + \")\", \"error\");\n updateCredentials.failure(\"onCredentialsExpired did not return valid credentials.\");\n }\n }, function(errorMsg) {\n self.log(\"onCredentialsExpired callback indicated failure! (\" + errorMsg + \")\", \"error\");\n updateCredentials.failure(\"onCredentialsExpired callback failed.\");\n });\n }\n else {\n self.log(\"onCredentialsExpired callback did not return a promise!\", \"error\");\n updateCredentials.failure(\"Unexpected return value for onCredentialsExpired.\");\n }\n\n return updateCredentials;\n }\n };\n\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this, additionalOptions, \"s3\");\n },\n\n _determineObjectPropertyValue: function(id, property) {\n var maybe = this._options.objectProperties[property],\n promise = new qq.Promise(),\n self = this;\n\n if (qq.isFunction(maybe)) {\n maybe = maybe(id);\n if (qq.isGenericPromise(maybe)) {\n promise = maybe;\n }\n else {\n promise.success(maybe);\n }\n }\n else if (qq.isString(maybe)) {\n promise.success(maybe);\n }\n\n promise.then(\n function success(value) {\n self[\"_\" + property + \"s\"][id] = value;\n },\n\n function failure(errorMsg) {\n qq.log(\"Problem determining \" + property + \" for ID \" + id + \" (\" + errorMsg + \")\", \"error\");\n }\n );\n\n return promise;\n },\n\n _determineBucket: function(id) {\n return this._determineObjectPropertyValue(id, \"bucket\");\n },\n\n _determineHost: function(id) {\n return this._determineObjectPropertyValue(id, \"host\");\n },\n\n /**\n * Determine the file's key name and passes it to the caller via a promissory callback. This also may\n * delegate to an integrator-defined function that determines the file's key name on demand,\n * which also may be promissory.\n *\n * @param id ID of the file\n * @param filename Name of the file\n * @returns {qq.Promise} A promise that will be fulfilled when the key name has been determined (and will be passed to the caller via the success callback).\n * @private\n */\n _determineKeyName: function(id, filename) {\n /*jshint -W015*/\n var promise = new qq.Promise(),\n keynameLogic = this._options.objectProperties.key,\n extension = qq.getExtension(filename),\n onGetKeynameFailure = promise.failure,\n onGetKeynameSuccess = function(keyname, extension) {\n var keynameToUse = keyname;\n\n if (extension !== undefined) {\n keynameToUse += \".\" + extension;\n }\n\n promise.success(keynameToUse);\n };\n\n switch (keynameLogic) {\n case \"uuid\":\n onGetKeynameSuccess(this.getUuid(id), extension);\n break;\n case \"filename\":\n onGetKeynameSuccess(filename);\n break;\n default:\n if (qq.isFunction(keynameLogic)) {\n this._handleKeynameFunction(keynameLogic, id, onGetKeynameSuccess, onGetKeynameFailure);\n }\n else {\n this.log(keynameLogic + \" is not a valid value for the s3.keyname option!\", \"error\");\n onGetKeynameFailure();\n }\n }\n\n return promise;\n },\n\n /**\n * Called by the internal onUpload handler if the integrator has supplied a function to determine\n * the file's key name. The integrator's function may be promissory. We also need to fulfill\n * the promise contract associated with the caller as well.\n *\n * @param keynameFunc Integrator-supplied function that must be executed to determine the key name. May be promissory.\n * @param id ID of the associated file\n * @param successCallback Invoke this if key name retrieval is successful, passing in the key name.\n * @param failureCallback Invoke this if key name retrieval was unsuccessful.\n * @private\n */\n _handleKeynameFunction: function(keynameFunc, id, successCallback, failureCallback) {\n var self = this,\n onSuccess = function(keyname) {\n successCallback(keyname);\n },\n onFailure = function(reason) {\n self.log(qq.format(\"Failed to retrieve key name for {}. Reason: {}\", id, reason || \"null\"), \"error\");\n failureCallback(reason);\n },\n keyname = keynameFunc.call(this, id);\n\n if (qq.isGenericPromise(keyname)) {\n keyname.then(onSuccess, onFailure);\n }\n /*jshint -W116*/\n else if (keyname == null) {\n onFailure();\n }\n else {\n onSuccess(keyname);\n }\n },\n\n _getEndpointSpecificParams: function(id, response, maybeXhr) {\n var params = {\n key: this.getKey(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n bucket: this.getBucket(id)\n };\n\n if (maybeXhr && maybeXhr.getResponseHeader(\"ETag\")) {\n params.etag = maybeXhr.getResponseHeader(\"ETag\");\n }\n else if (response.etag) {\n params.etag = response.etag;\n }\n\n return params;\n },\n\n // Hooks into the base internal `_onSubmitDelete` to add key and bucket params to the delete file request.\n _onSubmitDelete: function(id, onSuccessCallback) {\n var additionalMandatedParams = {\n key: this.getKey(id),\n bucket: this.getBucket(id)\n };\n\n return qq.FineUploaderBasic.prototype._onSubmitDelete.call(this, id, onSuccessCallback, additionalMandatedParams);\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.s3Key == null) {\n throw new qq.Error(\"Did not find s3Key property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedKeys[id] = sessionData.s3Key;\n this._cannedBuckets[id] = sessionData.s3Bucket;\n }\n\n return id;\n }\n });\n}());\n","/* globals qq, CryptoJS */\n\n// IE 10 does not support Uint8ClampedArray. We don't need it, but CryptoJS attempts to reference it\n// inside a conditional via an instanceof check, which breaks S3 v4 signatures for chunked uploads.\nif (!window.Uint8ClampedArray) {\n window.Uint8ClampedArray = function() {};\n}\n/**\n * Handles signature determination for HTML Form Upload requests and Multipart Uploader requests (via the S3 REST API).\n *\n * If the S3 requests are to be signed server side, this module will send a POST request to the server in an attempt\n * to solicit signatures for various S3-related requests. This module also parses the response and attempts\n * to determine if the effort was successful.\n *\n * If the S3 requests are to be signed client-side, without the help of a server, this module will utilize CryptoJS to\n * sign the requests directly in the browser and send them off to S3.\n *\n * @param o Options associated with all such requests\n * @returns {{getSignature: Function}} API method used to initiate the signature request.\n * @constructor\n */\nqq.s3.RequestSigner = function(o) {\n \"use strict\";\n\n var requester,\n thisSignatureRequester = this,\n pendingSignatures = {},\n options = {\n expectingPolicy: false,\n method: \"POST\",\n signatureSpec: {\n drift: 0,\n credentialsProvider: {},\n endpoint: null,\n customHeaders: {},\n version: 2\n },\n maxConnections: 3,\n endpointStore: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n },\n credentialsProvider,\n\n generateHeaders = function(signatureConstructor, signature, promise) {\n var headers = signatureConstructor.getHeaders();\n\n if (options.signatureSpec.version === 4) {\n headers.Authorization = qq.s3.util.V4_ALGORITHM_PARAM_VALUE +\n \" Credential=\" + options.signatureSpec.credentialsProvider.get().accessKey + \"/\" +\n qq.s3.util.getCredentialsDate(signatureConstructor.getRequestDate()) + \"/\" +\n options.signatureSpec.region + \"/\" +\n \"s3/aws4_request,\" +\n \"SignedHeaders=\" + signatureConstructor.getSignedHeaders() + \",\" +\n \"Signature=\" + signature;\n }\n else {\n headers.Authorization = \"AWS \" + options.signatureSpec.credentialsProvider.get().accessKey + \":\" + signature;\n }\n\n promise.success(headers, signatureConstructor.getEndOfUrl());\n },\n\n v2 = {\n getStringToSign: function(signatureSpec) {\n return qq.format(\"{}\\n{}\\n{}\\n\\n{}/{}/{}\",\n signatureSpec.method,\n signatureSpec.contentMd5 || \"\",\n signatureSpec.contentType || \"\",\n signatureSpec.headersStr || \"\\n\",\n signatureSpec.bucket,\n signatureSpec.endOfUrl);\n },\n\n signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {\n var headersWordArray = qq.CryptoJS.enc.Utf8.parse(headersStr),\n headersHmacSha1 = qq.CryptoJS.HmacSHA1(headersWordArray, credentialsProvider.get().secretKey),\n headersHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(headersHmacSha1);\n\n generateHeaders(signatureConstructor, headersHmacSha1Base64, signatureEffort);\n },\n\n signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var policyStr = JSON.stringify(policy),\n policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr),\n base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray),\n policyHmacSha1 = qq.CryptoJS.HmacSHA1(base64Policy, credentialsProvider.get().secretKey),\n policyHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(policyHmacSha1);\n\n signatureEffort.success({\n policy: base64Policy,\n signature: policyHmacSha1Base64\n }, updatedAccessKey, updatedSessionToken);\n }\n },\n\n v4 = {\n getCanonicalQueryString: function(endOfUri) {\n var queryParamIdx = endOfUri.indexOf(\"?\"),\n canonicalQueryString = \"\",\n encodedQueryParams, encodedQueryParamNames, queryStrings;\n\n if (queryParamIdx >= 0) {\n encodedQueryParams = {};\n queryStrings = endOfUri.substr(queryParamIdx + 1).split(\"&\");\n\n qq.each(queryStrings, function(idx, queryString) {\n var nameAndVal = queryString.split(\"=\"),\n paramVal = nameAndVal[1];\n\n if (paramVal == null) {\n paramVal = \"\";\n }\n\n encodedQueryParams[encodeURIComponent(nameAndVal[0])] = encodeURIComponent(paramVal);\n });\n\n encodedQueryParamNames = Object.keys(encodedQueryParams).sort();\n encodedQueryParamNames.forEach(function(encodedQueryParamName, idx) {\n canonicalQueryString += encodedQueryParamName + \"=\" + encodedQueryParams[encodedQueryParamName];\n if (idx < encodedQueryParamNames.length - 1) {\n canonicalQueryString += \"&\";\n }\n });\n }\n\n return canonicalQueryString;\n },\n\n getCanonicalRequest: function(signatureSpec) {\n return qq.format(\"{}\\n{}\\n{}\\n{}\\n{}\\n{}\",\n signatureSpec.method,\n v4.getCanonicalUri(signatureSpec.endOfUrl),\n v4.getCanonicalQueryString(signatureSpec.endOfUrl),\n signatureSpec.headersStr || \"\\n\",\n v4.getSignedHeaders(signatureSpec.headerNames),\n signatureSpec.hashedContent);\n },\n\n getCanonicalUri: function(endOfUri) {\n var path = endOfUri,\n queryParamIdx = endOfUri.indexOf(\"?\");\n\n if (queryParamIdx > 0) {\n path = endOfUri.substr(0, queryParamIdx);\n }\n return \"/\" + path;\n },\n\n getEncodedHashedPayload: function(body) {\n var promise = new qq.Promise(),\n reader;\n\n if (qq.isBlob(body)) {\n // TODO hash blob in webworker if this becomes a notable perf issue\n reader = new FileReader();\n reader.onloadend = function(e) {\n if (e.target.readyState === FileReader.DONE) {\n if (e.target.error) {\n promise.failure(e.target.error);\n }\n else {\n var wordArray = qq.CryptoJS.lib.WordArray.create(e.target.result);\n promise.success(qq.CryptoJS.SHA256(wordArray).toString());\n }\n }\n };\n reader.readAsArrayBuffer(body);\n }\n else {\n body = body || \"\";\n promise.success(qq.CryptoJS.SHA256(body).toString());\n }\n\n return promise;\n },\n\n getScope: function(date, region) {\n return qq.s3.util.getCredentialsDate(date) + \"/\" +\n region + \"/s3/aws4_request\";\n },\n\n getStringToSign: function(signatureSpec) {\n var canonicalRequest = v4.getCanonicalRequest(signatureSpec),\n date = qq.s3.util.getV4PolicyDate(signatureSpec.date, signatureSpec.drift),\n hashedRequest = qq.CryptoJS.SHA256(canonicalRequest).toString(),\n scope = v4.getScope(signatureSpec.date, options.signatureSpec.region),\n stringToSignTemplate = \"AWS4-HMAC-SHA256\\n{}\\n{}\\n{}\";\n\n return {\n hashed: qq.format(stringToSignTemplate, date, scope, hashedRequest),\n raw: qq.format(stringToSignTemplate, date, scope, canonicalRequest)\n };\n },\n\n getSignedHeaders: function(headerNames) {\n var signedHeaders = \"\";\n\n headerNames.forEach(function(headerName, idx) {\n signedHeaders += headerName.toLowerCase();\n\n if (idx < headerNames.length - 1) {\n signedHeaders += \";\";\n }\n });\n\n return signedHeaders;\n },\n\n signApiRequest: function(signatureConstructor, headersStr, signatureEffort) {\n var secretKey = credentialsProvider.get().secretKey,\n headersPattern = /.+\\n.+\\n(\\d+)\\/(.+)\\/s3\\/.+\\n(.+)/,\n matches = headersPattern.exec(headersStr),\n dateKey, dateRegionKey, dateRegionServiceKey, signingKey;\n\n dateKey = qq.CryptoJS.HmacSHA256(matches[1], \"AWS4\" + secretKey);\n dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);\n dateRegionServiceKey = qq.CryptoJS.HmacSHA256(\"s3\", dateRegionKey);\n signingKey = qq.CryptoJS.HmacSHA256(\"aws4_request\", dateRegionServiceKey);\n\n generateHeaders(signatureConstructor, qq.CryptoJS.HmacSHA256(headersStr, signingKey), signatureEffort);\n },\n\n signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var policyStr = JSON.stringify(policy),\n policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr),\n base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray),\n secretKey = credentialsProvider.get().secretKey,\n credentialPattern = /.+\\/(.+)\\/(.+)\\/s3\\/aws4_request/,\n credentialCondition = (function() {\n var credential = null;\n qq.each(policy.conditions, function(key, condition) {\n var val = condition[\"x-amz-credential\"];\n if (val) {\n credential = val;\n return false;\n }\n });\n return credential;\n }()),\n matches, dateKey, dateRegionKey, dateRegionServiceKey, signingKey;\n\n matches = credentialPattern.exec(credentialCondition);\n dateKey = qq.CryptoJS.HmacSHA256(matches[1], \"AWS4\" + secretKey);\n dateRegionKey = qq.CryptoJS.HmacSHA256(matches[2], dateKey);\n dateRegionServiceKey = qq.CryptoJS.HmacSHA256(\"s3\", dateRegionKey);\n signingKey = qq.CryptoJS.HmacSHA256(\"aws4_request\", dateRegionServiceKey);\n\n signatureEffort.success({\n policy: base64Policy,\n signature: qq.CryptoJS.HmacSHA256(base64Policy, signingKey).toString()\n }, updatedAccessKey, updatedSessionToken);\n }\n };\n\n qq.extend(options, o, true);\n credentialsProvider = options.signatureSpec.credentialsProvider;\n\n function handleSignatureReceived(id, xhrOrXdr, isError) {\n var responseJson = xhrOrXdr.responseText,\n pendingSignatureData = pendingSignatures[id],\n promise = pendingSignatureData.promise,\n signatureConstructor = pendingSignatureData.signatureConstructor,\n errorMessage, response;\n\n delete pendingSignatures[id];\n\n // Attempt to parse what we would expect to be a JSON response\n if (responseJson) {\n try {\n response = qq.parseJson(responseJson);\n }\n catch (error) {\n options.log(\"Error attempting to parse signature response: \" + error, \"error\");\n }\n }\n\n // If the response is parsable and contains an `error` property, use it as the error message\n if (response && response.error) {\n isError = true;\n errorMessage = response.error;\n }\n // If we have received a parsable response, and it has an `invalid` property,\n // the policy document or request headers may have been tampered with client-side.\n else if (response && response.invalid) {\n isError = true;\n errorMessage = \"Invalid policy document or request headers!\";\n }\n // Make sure the response contains policy & signature properties\n else if (response) {\n if (options.expectingPolicy && !response.policy) {\n isError = true;\n errorMessage = \"Response does not include the base64 encoded policy!\";\n }\n else if (!response.signature) {\n isError = true;\n errorMessage = \"Response does not include the signature!\";\n }\n }\n // Something unknown went wrong\n else {\n isError = true;\n errorMessage = \"Received an empty or invalid response from the server!\";\n }\n\n if (isError) {\n if (errorMessage) {\n options.log(errorMessage, \"error\");\n }\n\n promise.failure(errorMessage);\n }\n else if (signatureConstructor) {\n generateHeaders(signatureConstructor, response.signature, promise);\n }\n else {\n promise.success(response);\n }\n }\n\n function getStringToSignArtifacts(id, version, requestInfo) {\n var promise = new qq.Promise(),\n method = \"POST\",\n headerNames = [],\n headersStr = \"\",\n now = new Date(),\n endOfUrl, signatureSpec, toSign,\n\n generateStringToSign = function(requestInfo) {\n var contentMd5,\n headerIndexesToRemove = [];\n\n qq.each(requestInfo.headers, function(name) {\n headerNames.push(name);\n });\n headerNames.sort();\n\n qq.each(headerNames, function(idx, headerName) {\n if (qq.indexOf(qq.s3.util.UNSIGNABLE_REST_HEADER_NAMES, headerName) < 0) {\n headersStr += headerName.toLowerCase() + \":\" + requestInfo.headers[headerName].trim() + \"\\n\";\n }\n else if (headerName === \"Content-MD5\") {\n contentMd5 = requestInfo.headers[headerName];\n }\n else {\n headerIndexesToRemove.unshift(idx);\n }\n });\n\n qq.each(headerIndexesToRemove, function(idx, headerIdx) {\n headerNames.splice(headerIdx, 1);\n });\n\n signatureSpec = {\n bucket: requestInfo.bucket,\n contentMd5: contentMd5,\n contentType: requestInfo.contentType,\n date: now,\n drift: options.signatureSpec.drift,\n endOfUrl: endOfUrl,\n hashedContent: requestInfo.hashedContent,\n headerNames: headerNames,\n headersStr: headersStr,\n method: method\n };\n\n toSign = version === 2 ? v2.getStringToSign(signatureSpec) : v4.getStringToSign(signatureSpec);\n\n return {\n date: now,\n endOfUrl: endOfUrl,\n signedHeaders: version === 4 ? v4.getSignedHeaders(signatureSpec.headerNames) : null,\n toSign: version === 4 ? toSign.hashed : toSign,\n toSignRaw: version === 4 ? toSign.raw : toSign\n };\n };\n\n /*jshint indent:false */\n switch (requestInfo.type) {\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_ABORT:\n method = \"DELETE\";\n endOfUrl = qq.format(\"uploadId={}\", requestInfo.uploadId);\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_INITIATE:\n endOfUrl = \"uploads\";\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_COMPLETE:\n endOfUrl = qq.format(\"uploadId={}\", requestInfo.uploadId);\n break;\n case thisSignatureRequester.REQUEST_TYPE.MULTIPART_UPLOAD:\n method = \"PUT\";\n endOfUrl = qq.format(\"partNumber={}&uploadId={}\", requestInfo.partNum, requestInfo.uploadId);\n break;\n }\n\n endOfUrl = requestInfo.key + \"?\" + endOfUrl;\n\n if (version === 4) {\n v4.getEncodedHashedPayload(requestInfo.content).then(function(hashedContent) {\n requestInfo.headers[\"x-amz-content-sha256\"] = hashedContent;\n requestInfo.headers.Host = requestInfo.host;\n requestInfo.headers[\"x-amz-date\"] = qq.s3.util.getV4PolicyDate(now, options.signatureSpec.drift);\n requestInfo.hashedContent = hashedContent;\n\n promise.success(generateStringToSign(requestInfo));\n }, function (err) {\n promise.failure(err);\n });\n }\n else {\n promise.success(generateStringToSign(requestInfo));\n }\n\n return promise;\n }\n\n function determineSignatureClientSide(id, toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken) {\n var updatedHeaders;\n\n // REST API request\n if (toBeSigned.signatureConstructor) {\n if (updatedSessionToken) {\n updatedHeaders = toBeSigned.signatureConstructor.getHeaders();\n updatedHeaders[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken;\n toBeSigned.signatureConstructor.withHeaders(updatedHeaders);\n }\n\n toBeSigned.signatureConstructor.getToSign(id).then(function(signatureArtifacts) {\n signApiRequest(toBeSigned.signatureConstructor, signatureArtifacts.stringToSign, signatureEffort);\n }, function (err) {\n signatureEffort.failure(err);\n });\n }\n // Form upload (w/ policy document)\n else {\n updatedSessionToken && qq.s3.util.refreshPolicyCredentials(toBeSigned, updatedSessionToken);\n signPolicy(toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n }\n\n function signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken) {\n if (options.signatureSpec.version === 4) {\n v4.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n else {\n v2.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken);\n }\n }\n\n function signApiRequest(signatureConstructor, headersStr, signatureEffort) {\n if (options.signatureSpec.version === 4) {\n v4.signApiRequest(signatureConstructor, headersStr, signatureEffort);\n }\n else {\n v2.signApiRequest(signatureConstructor, headersStr, signatureEffort);\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n contentType: \"application/json; charset=utf-8\",\n endpointStore: {\n get: function() {\n return options.signatureSpec.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.signatureSpec.customHeaders,\n log: options.log,\n onComplete: handleSignatureReceived,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * On success, an object containing the parsed JSON response will be passed into the success handler if the\n * request succeeds. Otherwise an error message will be passed into the failure method.\n *\n * @param id File ID.\n * @param toBeSigned an Object that holds the item(s) to be signed\n * @returns {qq.Promise} A promise that is fulfilled when the response has been received.\n */\n getSignature: function(id, toBeSigned) {\n var params = toBeSigned,\n signatureConstructor = toBeSigned.signatureConstructor,\n signatureEffort = new qq.Promise(),\n queryParams;\n\n if (options.signatureSpec.version === 4) {\n queryParams = {v4: true};\n }\n\n if (credentialsProvider.get().secretKey && qq.CryptoJS) {\n if (credentialsProvider.get().expiration.getTime() > Date.now()) {\n determineSignatureClientSide(id, toBeSigned, signatureEffort);\n }\n // If credentials are expired, ask for new ones before attempting to sign request\n else {\n credentialsProvider.onExpired().then(function() {\n determineSignatureClientSide(id, toBeSigned,\n signatureEffort,\n credentialsProvider.get().accessKey,\n credentialsProvider.get().sessionToken);\n }, function(errorMsg) {\n options.log(\"Attempt to update expired credentials apparently failed! Unable to sign request. \", \"error\");\n signatureEffort.failure(\"Unable to sign request - expired credentials.\");\n });\n }\n }\n else {\n options.log(\"Submitting S3 signature request for \" + id);\n\n if (signatureConstructor) {\n signatureConstructor.getToSign(id).then(function(signatureArtifacts) {\n params = {headers: signatureArtifacts.stringToSignRaw};\n requester.initTransport(id)\n .withParams(params)\n .withQueryParams(queryParams)\n .send();\n }, function (err) {\n options.log(\"Failed to construct signature. \", \"error\");\n signatureEffort.failure(\"Failed to construct signature.\");\n });\n }\n else {\n requester.initTransport(id)\n .withParams(params)\n .withQueryParams(queryParams)\n .send();\n }\n\n pendingSignatures[id] = {\n promise: signatureEffort,\n signatureConstructor: signatureConstructor\n };\n }\n\n return signatureEffort;\n },\n\n constructStringToSign: function(type, bucket, host, key) {\n var headers = {},\n uploadId, content, contentType, partNum, artifacts;\n\n return {\n withHeaders: function(theHeaders) {\n headers = theHeaders;\n return this;\n },\n\n withUploadId: function(theUploadId) {\n uploadId = theUploadId;\n return this;\n },\n\n withContent: function(theContent) {\n content = theContent;\n return this;\n },\n\n withContentType: function(theContentType) {\n contentType = theContentType;\n return this;\n },\n\n withPartNum: function(thePartNum) {\n partNum = thePartNum;\n return this;\n },\n\n getToSign: function(id) {\n var sessionToken = credentialsProvider.get().sessionToken,\n promise = new qq.Promise(),\n adjustedDate = new Date(Date.now() + options.signatureSpec.drift);\n\n headers[\"x-amz-date\"] = adjustedDate.toUTCString();\n\n if (sessionToken) {\n headers[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken;\n }\n\n getStringToSignArtifacts(id, options.signatureSpec.version, {\n bucket: bucket,\n content: content,\n contentType: contentType,\n headers: headers,\n host: host,\n key: key,\n partNum: partNum,\n type: type,\n uploadId: uploadId\n }).then(function(_artifacts_) {\n artifacts = _artifacts_;\n promise.success({\n headers: (function() {\n if (contentType) {\n headers[\"Content-Type\"] = contentType;\n }\n\n delete headers.Host; // we don't want this to be set on the XHR-initiated request\n return headers;\n }()),\n date: artifacts.date,\n endOfUrl: artifacts.endOfUrl,\n signedHeaders: artifacts.signedHeaders,\n stringToSign: artifacts.toSign,\n stringToSignRaw: artifacts.toSignRaw\n });\n }, function (err) {\n promise.failure(err);\n });\n\n return promise;\n },\n\n getHeaders: function() {\n return qq.extend({}, headers);\n },\n\n getEndOfUrl: function() {\n return artifacts && artifacts.endOfUrl;\n },\n\n getRequestDate: function() {\n return artifacts && artifacts.date;\n },\n\n getSignedHeaders: function() {\n return artifacts && artifacts.signedHeaders;\n }\n };\n }\n });\n};\n\nqq.s3.RequestSigner.prototype.REQUEST_TYPE = {\n MULTIPART_INITIATE: \"multipart_initiate\",\n MULTIPART_COMPLETE: \"multipart_complete\",\n MULTIPART_ABORT: \"multipart_abort\",\n MULTIPART_UPLOAD: \"multipart_upload\"\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/*globals qq*/\n/**\n * Ajax requester used to send an [\"Initiate Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadInitiate.html)\n * request to S3 via the REST API.\n *\n * @param o Options from the caller - will override the defaults.\n * @constructor\n */\nqq.s3.InitiateMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingInitiateRequests = {},\n options = {\n filenameParam: \"qqfilename\",\n method: \"POST\",\n endpointStore: null,\n paramsStore: null,\n signatureSpec: null,\n aclStore: null,\n reducedRedundancy: false,\n serverSideEncryption: false,\n maxConnections: 3,\n getContentType: function(id) {},\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n getName: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Determine all headers for the \"Initiate MPU\" request, including the \"Authorization\" header, which must be determined\n * by the local server. This is a promissory function. If the server responds with a signature, the headers\n * (including the Authorization header) will be passed into the success method of the promise. Otherwise, the failure\n * method on the promise will be called.\n *\n * @param id Associated file ID\n * @returns {qq.Promise}\n */\n function getHeaders(id) {\n var bucket = options.getBucket(id),\n host = options.getHost(id),\n headers = {},\n promise = new qq.Promise(),\n key = options.getKey(id),\n signatureConstructor;\n\n headers[\"x-amz-acl\"] = options.aclStore.get(id);\n\n if (options.reducedRedundancy) {\n headers[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE;\n }\n\n if (options.serverSideEncryption) {\n headers[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE;\n }\n\n headers[qq.s3.util.AWS_PARAM_PREFIX + options.filenameParam] = encodeURIComponent(options.getName(id));\n\n qq.each(options.paramsStore.get(id), function(name, val) {\n if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) {\n headers[name] = val;\n }\n else {\n headers[qq.s3.util.AWS_PARAM_PREFIX + name] = encodeURIComponent(val);\n }\n });\n\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_INITIATE, bucket, host, key)\n .withContentType(options.getContentType(id))\n .withHeaders(headers);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Initiate MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleInitiateRequestComplete(id, xhr, isError) {\n var promise = pendingInitiateRequests[id],\n domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n uploadIdElements, messageElements, uploadId, errorMessage, status;\n\n delete pendingInitiateRequests[id];\n\n // The base ajax requester may declare the request to be a failure based on status code.\n if (isError) {\n status = xhr.status;\n\n messageElements = responseDoc.getElementsByTagName(\"Message\");\n if (messageElements.length > 0) {\n errorMessage = messageElements[0].textContent;\n }\n }\n // If the base ajax requester has not declared this a failure, make sure we can retrieve the uploadId from the response.\n else {\n uploadIdElements = responseDoc.getElementsByTagName(\"UploadId\");\n if (uploadIdElements.length > 0) {\n uploadId = uploadIdElements[0].textContent;\n }\n else {\n errorMessage = \"Upload ID missing from request\";\n }\n }\n\n // Either fail the promise (passing a descriptive error message) or declare it a success (passing the upload ID)\n if (uploadId === undefined) {\n if (errorMessage) {\n options.log(qq.format(\"Specific problem detected initiating multipart upload request for {}: '{}'.\", id, errorMessage), \"error\");\n }\n else {\n options.log(qq.format(\"Unexplained error with initiate multipart upload request for {}. Status code {}.\", id, status), \"error\");\n }\n\n promise.failure(\"Problem initiating upload request.\", xhr);\n }\n else {\n options.log(qq.format(\"Initiate multipart upload request successful for {}. Upload ID is {}\", id, uploadId));\n promise.success(uploadId, xhr);\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n method: options.method,\n contentType: null,\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleInitiateRequestComplete,\n successfulResponseCodes: {\n POST: [200]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Initiate MPU\" request to AWS via the REST API. First, though, we must get a signature from the\n * local server for the request. If all is successful, the uploadId from AWS will be passed into the promise's\n * success handler. Otherwise, an error message will ultimately be passed into the failure method.\n *\n * @param id The ID associated with the file\n * @returns {qq.Promise}\n */\n send: function(id) {\n var promise = new qq.Promise();\n\n getHeaders(id).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 initiate multipart upload request for \" + id);\n\n pendingInitiateRequests[id] = promise;\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .send();\n }, promise.failure);\n\n return promise;\n }\n });\n};\n","/*globals qq*/\n/**\n * Ajax requester used to send an [\"Complete Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadComplete.html)\n * request to S3 via the REST API.\n *\n * @param o Options passed by the creator, to overwrite any default option values.\n * @constructor\n */\nqq.s3.CompleteMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingCompleteRequests = {},\n options = {\n method: \"POST\",\n contentType: \"text/xml\",\n endpointStore: null,\n signatureSpec: null,\n maxConnections: 3,\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n // Transport for requesting signatures (for the \"Complete\" requests) from the local server\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Attach all required headers (including Authorization) to the \"Complete\" request. This is a promissory function\n * that will fulfill the associated promise once all headers have been attached or when an error has occurred that\n * prevents headers from being attached.\n *\n * @returns {qq.Promise}\n */\n function getHeaders(id, uploadId, body) {\n var headers = {},\n promise = new qq.Promise(),\n bucket = options.getBucket(id),\n host = options.getHost(id),\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_COMPLETE, bucket, host, options.getKey(id))\n .withUploadId(uploadId)\n .withContent(body)\n .withContentType(\"application/xml; charset=UTF-8\");\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Complete MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleCompleteRequestComplete(id, xhr, isError) {\n var promise = pendingCompleteRequests[id],\n domParser = new DOMParser(),\n bucket = options.getBucket(id),\n key = options.getKey(id),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n bucketEls = responseDoc.getElementsByTagName(\"Bucket\"),\n keyEls = responseDoc.getElementsByTagName(\"Key\");\n\n delete pendingCompleteRequests[id];\n\n options.log(qq.format(\"Complete response status {}, body = {}\", xhr.status, xhr.responseText));\n\n // If the base requester has determine this a failure, give up.\n if (isError) {\n options.log(qq.format(\"Complete Multipart Upload request for {} failed with status {}.\", id, xhr.status), \"error\");\n }\n else {\n // Make sure the correct bucket and key has been specified in the XML response from AWS.\n if (bucketEls.length && keyEls.length) {\n if (bucketEls[0].textContent !== bucket) {\n isError = true;\n options.log(qq.format(\"Wrong bucket in response to Complete Multipart Upload request for {}.\", id), \"error\");\n }\n\n // TODO Compare key name from response w/ expected key name if AWS ever fixes the encoding of key names in this response.\n }\n else {\n isError = true;\n options.log(qq.format(\"Missing bucket and/or key in response to Complete Multipart Upload request for {}.\", id), \"error\");\n }\n }\n\n if (isError) {\n promise.failure(\"Problem combining the file parts!\", xhr);\n }\n else {\n promise.success({}, xhr);\n }\n }\n\n /**\n * @param etagEntries Array of objects containing `etag` values and their associated `part` numbers.\n * @returns {string} XML string containing the body to send with the \"Complete\" request\n */\n function getCompleteRequestBody(etagEntries) {\n var doc = document.implementation.createDocument(null, \"CompleteMultipartUpload\", null);\n\n // The entries MUST be sorted by part number, per the AWS API spec.\n etagEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(etagEntries, function(idx, etagEntry) {\n var part = etagEntry.part,\n etag = etagEntry.etag,\n partEl = doc.createElement(\"Part\"),\n partNumEl = doc.createElement(\"PartNumber\"),\n partNumTextEl = doc.createTextNode(part),\n etagTextEl = doc.createTextNode(etag),\n etagEl = doc.createElement(\"ETag\");\n\n etagEl.appendChild(etagTextEl);\n partNumEl.appendChild(partNumTextEl);\n partEl.appendChild(partNumEl);\n partEl.appendChild(etagEl);\n qq(doc).children()[0].appendChild(partEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n method: options.method,\n contentType: \"application/xml; charset=UTF-8\",\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleCompleteRequestComplete,\n successfulResponseCodes: {\n POST: [200]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Complete\" request and fulfills the returned promise when the success of this request is known.\n *\n * @param id ID associated with the file.\n * @param uploadId AWS uploadId for this file\n * @param etagEntries Array of objects containing `etag` values and their associated `part` numbers.\n * @returns {qq.Promise}\n */\n send: function(id, uploadId, etagEntries) {\n var promise = new qq.Promise(),\n body = getCompleteRequestBody(etagEntries);\n\n getHeaders(id, uploadId, body).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 complete multipart upload request for \" + id);\n\n pendingCompleteRequests[id] = promise;\n delete headers[\"Content-Type\"];\n\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .withPayload(body)\n .send();\n }, promise.failure);\n\n return promise;\n }\n });\n};\n","/*globals qq */\n/**\n * Ajax requester used to send an [\"Abort Multipart Upload\"](http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadAbort.html)\n * request to S3 via the REST API.\n\n * @param o\n * @constructor\n */\nqq.s3.AbortMultipartAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n endpointStore: null,\n signatureSpec: null,\n maxConnections: 3,\n getBucket: function(id) {},\n getHost: function(id) {},\n getKey: function(id) {},\n log: function(str, level) {}\n },\n getSignatureAjaxRequester;\n\n qq.extend(options, o);\n\n // Transport for requesting signatures (for the \"Complete\" requests) from the local server\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n endpointStore: options.endpointStore,\n signatureSpec: options.signatureSpec,\n cors: options.cors,\n log: options.log\n });\n\n /**\n * Attach all required headers (including Authorization) to the \"Abort\" request. This is a promissory function\n * that will fulfill the associated promise once all headers have been attached or when an error has occurred that\n * prevents headers from being attached.\n *\n * @param id Associated file ID\n * @param uploadId ID of the associated upload, according to AWS\n * @returns {qq.Promise}\n */\n function getHeaders(id, uploadId) {\n var headers = {},\n promise = new qq.Promise(),\n bucket = options.getBucket(id),\n host = options.getHost(id),\n signatureConstructor = getSignatureAjaxRequester.constructStringToSign\n (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, options.getKey(id))\n .withUploadId(uploadId);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n }\n\n /**\n * Called by the base ajax requester when the response has been received. We definitively determine here if the\n * \"Abort MPU\" request has been a success or not.\n *\n * @param id ID associated with the file.\n * @param xhr `XMLHttpRequest` object containing the response, among other things.\n * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code).\n */\n function handleAbortRequestComplete(id, xhr, isError) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(xhr.responseText, \"application/xml\"),\n errorEls = responseDoc.getElementsByTagName(\"Error\"),\n awsErrorMsg;\n\n options.log(qq.format(\"Abort response status {}, body = {}\", xhr.status, xhr.responseText));\n\n // If the base requester has determine this a failure, give up.\n if (isError) {\n options.log(qq.format(\"Abort Multipart Upload request for {} failed with status {}.\", id, xhr.status), \"error\");\n }\n else {\n // Make sure the correct bucket and key has been specified in the XML response from AWS.\n if (errorEls.length) {\n isError = true;\n awsErrorMsg = responseDoc.getElementsByTagName(\"Message\")[0].textContent;\n options.log(qq.format(\"Failed to Abort Multipart Upload request for {}. Error: {}\", id, awsErrorMsg), \"error\");\n }\n else {\n options.log(qq.format(\"Abort MPU request succeeded for file ID {}.\", id));\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [\"DELETE\"],\n method: options.method,\n contentType: null,\n endpointStore: options.endpointStore,\n maxConnections: options.maxConnections,\n allowXRequestedWithAndCacheControl: false, //These headers are not necessary & would break some installations if added\n log: options.log,\n onComplete: handleAbortRequestComplete,\n successfulResponseCodes: {\n DELETE: [204]\n }\n }));\n\n qq.extend(this, {\n /**\n * Sends the \"Abort\" request.\n *\n * @param id ID associated with the file.\n * @param uploadId AWS uploadId for this file\n */\n send: function(id, uploadId) {\n getHeaders(id, uploadId).then(function(headers, endOfUrl) {\n options.log(\"Submitting S3 Abort multipart upload request for \" + id);\n requester.initTransport(id)\n .withPath(endOfUrl)\n .withHeaders(headers)\n .send();\n });\n }\n });\n};\n","/*globals qq */\n/**\n * Upload handler used by the upload to S3 module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to S3 buckets via the associated AWS API.\n *\n * If chunking is supported and enabled, the S3 Multipart Upload REST API is utilized.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.s3.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var getName = proxy.getName,\n log = proxy.log,\n clockDrift = spec.clockDrift,\n expectedStatus = 200,\n onGetBucket = spec.getBucket,\n onGetHost = spec.getHost,\n onGetKeyName = spec.getKeyName,\n filenameParam = spec.filenameParam,\n paramsStore = spec.paramsStore,\n endpointStore = spec.endpointStore,\n aclStore = spec.aclStore,\n reducedRedundancy = spec.objectProperties.reducedRedundancy,\n region = spec.objectProperties.region,\n serverSideEncryption = spec.objectProperties.serverSideEncryption,\n validation = spec.validation,\n signature = qq.extend({region: region, drift: clockDrift}, spec.signature),\n handler = this,\n credentialsProvider = spec.signature.credentialsProvider,\n\n chunked = {\n // Sends a \"Complete Multipart Upload\" request and then signals completion of the upload\n // when the response to this request has been parsed.\n combine: function(id) {\n var uploadId = handler._getPersistableData(id).uploadId,\n etagMap = handler._getPersistableData(id).etags,\n result = new qq.Promise();\n\n requesters.completeMultipart.send(id, uploadId, etagMap).then(\n result.success,\n\n function failure(reason, xhr) {\n result.failure(upload.done(id, xhr).response, xhr);\n }\n );\n\n return result;\n },\n\n // The last step in handling a chunked upload. This is called after each chunk has been sent.\n // The request may be successful, or not. If it was successful, we must extract the \"ETag\" element\n // in the XML response and store that along with the associated part number.\n // We need these items to \"Complete\" the multipart upload after all chunks have been successfully sent.\n done: function(id, xhr, chunkIdx) {\n var response = upload.response.parse(id, xhr),\n etag;\n\n if (response.success) {\n etag = xhr.getResponseHeader(\"ETag\");\n\n if (!handler._getPersistableData(id).etags) {\n handler._getPersistableData(id).etags = [];\n }\n handler._getPersistableData(id).etags.push({part: chunkIdx + 1, etag: etag});\n }\n },\n\n /**\n * Determines headers that must be attached to the chunked (Multipart Upload) request. One of these headers is an\n * Authorization value, which must be determined by asking the local server to sign the request first. So, this\n * function returns a promise. Once all headers are determined, the `success` method of the promise is called with\n * the headers object. If there was some problem determining the headers, we delegate to the caller's `failure`\n * callback.\n *\n * @param id File ID\n * @param chunkIdx Index of the chunk to PUT\n * @returns {qq.Promise}\n */\n initHeaders: function(id, chunkIdx, blob) {\n var headers = {},\n bucket = upload.bucket.getName(id),\n host = upload.host.getName(id),\n key = upload.key.urlSafe(id),\n promise = new qq.Promise(),\n signatureConstructor = requesters.restSignature.constructStringToSign\n (requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key)\n .withPartNum(chunkIdx + 1)\n .withContent(blob)\n .withUploadId(handler._getPersistableData(id).uploadId);\n\n // Ask the local server to sign the request. Use this signature to form the Authorization header.\n requesters.restSignature.getSignature(id + \".\" + chunkIdx, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure);\n\n return promise;\n },\n\n put: function(id, chunkIdx) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx),\n domain = spec.endpointStore.get(id),\n promise = new qq.Promise();\n\n // Add appropriate headers to the multipart upload request.\n // Once these have been determined (asynchronously) attach the headers and send the chunk.\n chunked.initHeaders(id, chunkIdx, chunkData.blob).then(function(headers, endOfUrl) {\n if (xhr._cancelled) {\n log(qq.format(\"Upload of item {}.{} cancelled. Upload will not start after successful signature request.\", id, chunkIdx));\n promise.failure({error: \"Chunk upload cancelled\"});\n }\n else {\n var url = domain + \"/\" + endOfUrl;\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n upload.track(id, xhr, chunkIdx).then(promise.success, promise.failure);\n xhr.open(\"PUT\", url, true);\n\n qq.each(headers, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n\n xhr.send(chunkData.blob);\n }\n }, function() {\n promise.failure({error: \"Problem signing the chunk!\"}, xhr);\n });\n\n return promise;\n },\n\n send: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n chunked.setup(id).then(\n // The \"Initiate\" request succeeded. We are ready to send the first chunk.\n function() {\n chunked.put(id, chunkIdx).then(promise.success, promise.failure);\n },\n\n // We were unable to initiate the chunked upload process.\n function(errorMessage, xhr) {\n promise.failure({error: errorMessage}, xhr);\n }\n );\n\n return promise;\n },\n\n /**\n * Sends an \"Initiate Multipart Upload\" request to S3 via the REST API, but only if the MPU has not already been\n * initiated.\n *\n * @param id Associated file ID\n * @returns {qq.Promise} A promise that is fulfilled when the initiate request has been sent and the response has been parsed.\n */\n setup: function(id) {\n var promise = new qq.Promise(),\n uploadId = handler._getPersistableData(id).uploadId,\n uploadIdPromise = new qq.Promise();\n\n if (!uploadId) {\n handler._getPersistableData(id).uploadId = uploadIdPromise;\n requesters.initiateMultipart.send(id).then(\n function(uploadId) {\n handler._getPersistableData(id).uploadId = uploadId;\n uploadIdPromise.success(uploadId);\n promise.success(uploadId);\n },\n function(errorMsg, xhr) {\n handler._getPersistableData(id).uploadId = null;\n promise.failure(errorMsg, xhr);\n uploadIdPromise.failure(errorMsg, xhr);\n }\n );\n }\n else if (uploadId instanceof qq.Promise) {\n uploadId.then(function(uploadId) {\n promise.success(uploadId);\n });\n }\n else {\n promise.success(uploadId);\n }\n\n return promise;\n }\n },\n\n requesters = {\n abortMultipart: new qq.s3.AbortMultipartAjaxRequester({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log,\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n }\n }),\n\n completeMultipart: new qq.s3.CompleteMultipartAjaxRequester({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log,\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n }\n }),\n\n initiateMultipart: new qq.s3.InitiateMultipartAjaxRequester({\n filenameParam: filenameParam,\n endpointStore: endpointStore,\n paramsStore: paramsStore,\n signatureSpec: signature,\n aclStore: aclStore,\n reducedRedundancy: reducedRedundancy,\n serverSideEncryption: serverSideEncryption,\n cors: spec.cors,\n log: log,\n getContentType: function(id) {\n return handler._getMimeType(id);\n },\n getBucket: function(id) {\n return upload.bucket.getName(id);\n },\n getHost: function(id) {\n return upload.host.getName(id);\n },\n getKey: function(id) {\n return upload.key.urlSafe(id);\n },\n getName: function(id) {\n return getName(id);\n }\n }),\n\n policySignature: new qq.s3.RequestSigner({\n expectingPolicy: true,\n signatureSpec: signature,\n cors: spec.cors,\n log: log\n }),\n\n restSignature: new qq.s3.RequestSigner({\n endpointStore: endpointStore,\n signatureSpec: signature,\n cors: spec.cors,\n log: log\n })\n },\n\n simple = {\n /**\n * Used for simple (non-chunked) uploads to determine the parameters to send along with the request. Part of this\n * process involves asking the local server to sign the request, so this function returns a promise. The promise\n * is fulfilled when all parameters are determined, or when we determine that all parameters cannot be calculated\n * due to some error.\n *\n * @param id File ID\n * @returns {qq.Promise}\n */\n initParams: function(id) {\n /*jshint -W040 */\n var customParams = paramsStore.get(id);\n customParams[filenameParam] = getName(id);\n\n return qq.s3.util.generateAwsParams({\n endpoint: endpointStore.get(id),\n clockDrift: clockDrift,\n params: customParams,\n type: handler._getMimeType(id),\n bucket: upload.bucket.getName(id),\n key: handler.getThirdPartyFileId(id),\n accessKey: credentialsProvider.get().accessKey,\n sessionToken: credentialsProvider.get().sessionToken,\n acl: aclStore.get(id),\n expectedStatus: expectedStatus,\n minFileSize: validation.minSizeLimit,\n maxFileSize: validation.maxSizeLimit,\n reducedRedundancy: reducedRedundancy,\n region: region,\n serverSideEncryption: serverSideEncryption,\n signatureVersion: signature.version,\n log: log\n },\n qq.bind(requesters.policySignature.getSignature, this, id));\n },\n\n send: function(id) {\n var promise = new qq.Promise(),\n xhr = handler._createXhr(id),\n fileOrBlob = handler.getFile(id);\n\n handler._registerProgressHandler(id);\n upload.track(id, xhr).then(promise.success, promise.failure);\n\n // Delegate to a function the sets up the XHR request and notifies us when it is ready to be sent, along w/ the payload.\n simple.setup(id, xhr, fileOrBlob).then(function(toSend) {\n log(\"Sending upload request for \" + id);\n xhr.send(toSend);\n }, promise.failure);\n\n return promise;\n },\n\n /**\n * Starts the upload process by delegating to an async function that determine parameters to be attached to the\n * request. If all params can be determined, we are called back with the params and the caller of this function is\n * informed by invoking the `success` method on the promise returned by this function, passing the payload of the\n * request. If some error occurs here, we delegate to a function that signals a failure for this upload attempt.\n *\n * Note that this is only used by the simple (non-chunked) upload process.\n *\n * @param id File ID\n * @param xhr XMLHttpRequest to use for the upload\n * @param fileOrBlob `File` or `Blob` to send\n * @returns {qq.Promise}\n */\n setup: function(id, xhr, fileOrBlob) {\n var formData = new FormData(),\n endpoint = endpointStore.get(id),\n url = endpoint,\n promise = new qq.Promise();\n\n simple.initParams(id).then(\n // Success - all params determined\n function(awsParams) {\n xhr.open(\"POST\", url, true);\n\n qq.obj2FormData(awsParams, formData);\n\n // AWS requires the file field be named \"file\".\n formData.append(\"file\", fileOrBlob);\n\n promise.success(formData);\n },\n\n // Failure - we couldn't determine some params (likely the signature)\n function(errorMessage) {\n promise.failure({error: errorMessage});\n }\n );\n\n return promise;\n }\n },\n\n upload = {\n /**\n * Note that this is called when an upload has reached a termination point,\n * regardless of success/failure. For example, it is called when we have\n * encountered an error during the upload or when the file may have uploaded successfully.\n *\n * @param id file ID\n */\n bucket: {\n promise: function(id) {\n var promise = new qq.Promise(),\n cachedBucket = handler._getFileState(id).bucket;\n\n if (cachedBucket) {\n promise.success(cachedBucket);\n }\n else {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n promise.success(bucket);\n }, promise.failure);\n }\n\n return promise;\n },\n\n getName: function(id) {\n return handler._getFileState(id).bucket;\n }\n },\n\n host: {\n promise: function(id) {\n var promise = new qq.Promise(),\n cachedHost = handler._getFileState(id).host;\n\n if (cachedHost) {\n promise.success(cachedHost);\n }\n else {\n onGetHost(id).then(function(host) {\n handler._getFileState(id).host = host;\n promise.success(host);\n }, promise.failure);\n }\n\n return promise;\n },\n\n getName: function(id) {\n return handler._getFileState(id).host;\n }\n },\n\n done: function(id, xhr) {\n var response = upload.response.parse(id, xhr),\n isError = response.success !== true;\n\n if (isError && upload.response.shouldReset(response.code)) {\n log(\"This is an unrecoverable error, we must restart the upload entirely on the next retry attempt.\", \"error\");\n response.reset = true;\n }\n\n return {\n success: !isError,\n response: response\n };\n },\n\n key: {\n promise: function(id) {\n var promise = new qq.Promise(),\n key = handler.getThirdPartyFileId(id);\n\n /* jshint eqnull:true */\n if (key == null) {\n handler._setThirdPartyFileId(id, promise);\n onGetKeyName(id, getName(id)).then(\n function(keyName) {\n handler._setThirdPartyFileId(id, keyName);\n promise.success(keyName);\n },\n function(errorReason) {\n handler._setThirdPartyFileId(id, null);\n promise.failure(errorReason);\n }\n );\n }\n else if (qq.isGenericPromise(key)) {\n key.then(promise.success, promise.failure);\n }\n else {\n promise.success(key);\n }\n\n return promise;\n },\n\n urlSafe: function(id) {\n var encodedKey = handler.getThirdPartyFileId(id);\n return qq.s3.util.uriEscapePath(encodedKey);\n }\n },\n\n response: {\n parse: function(id, xhr) {\n var response = {},\n parsedErrorProps;\n\n try {\n log(qq.format(\"Received response status {} with body: {}\", xhr.status, xhr.responseText));\n\n if (xhr.status === expectedStatus) {\n response.success = true;\n }\n else {\n parsedErrorProps = upload.response.parseError(xhr.responseText);\n\n if (parsedErrorProps) {\n response.error = parsedErrorProps.message;\n response.code = parsedErrorProps.code;\n }\n }\n }\n catch (error) {\n log(\"Error when attempting to parse xhr response text (\" + error.message + \")\", \"error\");\n }\n\n return response;\n },\n\n /**\n * This parses an XML response by extracting the \"Message\" and \"Code\" elements that accompany AWS error responses.\n *\n * @param awsResponseXml XML response from AWS\n * @returns {object} Object w/ `code` and `message` properties, or undefined if we couldn't find error info in the XML document.\n */\n parseError: function(awsResponseXml) {\n var parser = new DOMParser(),\n parsedDoc = parser.parseFromString(awsResponseXml, \"application/xml\"),\n errorEls = parsedDoc.getElementsByTagName(\"Error\"),\n errorDetails = {},\n codeEls, messageEls;\n\n if (errorEls.length) {\n codeEls = parsedDoc.getElementsByTagName(\"Code\");\n messageEls = parsedDoc.getElementsByTagName(\"Message\");\n\n if (messageEls.length) {\n errorDetails.message = messageEls[0].textContent;\n }\n\n if (codeEls.length) {\n errorDetails.code = codeEls[0].textContent;\n }\n\n return errorDetails;\n }\n },\n\n // Determine if the upload should be restarted on the next retry attempt\n // based on the error code returned in the response from AWS.\n shouldReset: function(errorCode) {\n /*jshint -W014 */\n return errorCode === \"EntityTooSmall\"\n || errorCode === \"InvalidPart\"\n || errorCode === \"InvalidPartOrder\"\n || errorCode === \"NoSuchUpload\";\n }\n },\n\n start: function(id, optChunkIdx) {\n var promise = new qq.Promise();\n\n upload.key.promise(id).then(function() {\n upload.bucket.promise(id).then(function() {\n upload.host.promise(id).then(function() {\n /* jshint eqnull:true */\n if (optChunkIdx == null) {\n simple.send(id).then(promise.success, promise.failure);\n }\n else {\n chunked.send(id, optChunkIdx).then(promise.success, promise.failure);\n }\n });\n });\n },\n function(errorReason) {\n promise.failure({error: errorReason});\n });\n\n return promise;\n },\n\n track: function(id, xhr, optChunkIdx) {\n var promise = new qq.Promise();\n\n xhr.onreadystatechange = function() {\n if (xhr.readyState === 4) {\n var result;\n\n /* jshint eqnull:true */\n if (optChunkIdx == null) {\n result = upload.done(id, xhr);\n promise[result.success ? \"success\" : \"failure\"](result.response, xhr);\n }\n else {\n chunked.done(id, xhr, optChunkIdx);\n result = upload.done(id, xhr);\n promise[result.success ? \"success\" : \"failure\"](result.response, xhr);\n }\n }\n };\n\n return promise;\n }\n };\n\n qq.extend(this, {\n uploadChunk: upload.start,\n uploadFile: upload.start\n });\n\n qq.extend(this, new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"s3\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var uploadId = handler._getPersistableData(id) && handler._getPersistableData(id).uploadId,\n existedInLocalStorage = handler._maybeDeletePersistedChunkData(id);\n\n if (uploadId !== undefined && existedInLocalStorage) {\n requesters.abortMultipart.send(id, uploadId);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return chunked.combine(id);\n },\n\n _getLocalStorageId: function(id) {\n var baseStorageId = super_._getLocalStorageId(id),\n bucketName = upload.bucket.getName(id);\n\n return baseStorageId + \"-\" + bucketName;\n }\n };\n });\n};\n","/*globals qq */\n/**\n * Upload handler used by the upload to S3 module that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to S3 buckets via the associated\n * AWS API.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.s3.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n clockDrift = options.clockDrift,\n onUuidChanged = proxy.onUuidChanged,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n onGetBucket = options.getBucket,\n onGetKeyName = options.getKeyName,\n filenameParam = options.filenameParam,\n paramsStore = options.paramsStore,\n endpointStore = options.endpointStore,\n aclStore = options.aclStore,\n reducedRedundancy = options.objectProperties.reducedRedundancy,\n region = options.objectProperties.region,\n serverSideEncryption = options.objectProperties.serverSideEncryption,\n validation = options.validation,\n signature = options.signature,\n successRedirectUrl = options.iframeSupport.localBlankPagePath,\n credentialsProvider = options.signature.credentialsProvider,\n getSignatureAjaxRequester = new qq.s3.RequestSigner({\n signatureSpec: signature,\n cors: options.cors,\n log: log\n });\n\n if (successRedirectUrl === undefined) {\n throw new Error(\"successRedirectEndpoint MUST be defined if you intend to use browsers that do not support the File API!\");\n }\n\n /**\n * Attempt to parse the contents of an iframe after receiving a response from the server. If the contents cannot be\n * read (perhaps due to a security error) it is safe to assume that the upload was not successful since Amazon should\n * have redirected to a known endpoint that should provide a parseable response.\n *\n * @param id ID of the associated file\n * @param iframe target of the form submit\n * @returns {boolean} true if the contents can be read, false otherwise\n */\n function isValidResponse(id, iframe) {\n var response,\n endpoint = options.endpointStore.get(id),\n bucket = handler._getFileState(id).bucket,\n doc,\n innerHtml,\n responseData;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n responseData = qq.s3.util.parseIframeResponse(iframe);\n if (responseData.bucket === bucket &&\n responseData.key === qq.s3.util.encodeQueryStringParam(handler.getThirdPartyFileId(id))) {\n\n return true;\n }\n\n log(\"Response from AWS included an unexpected bucket or key name.\", \"error\");\n\n }\n catch (error) {\n log(\"Error when attempting to parse form upload response (\" + error.message + \")\", \"error\");\n }\n\n return false;\n }\n\n function generateAwsParams(id) {\n /*jshint -W040 */\n var customParams = paramsStore.get(id);\n\n customParams[filenameParam] = getName(id);\n\n return qq.s3.util.generateAwsParams({\n endpoint: endpointStore.get(id),\n clockDrift: clockDrift,\n params: customParams,\n bucket: handler._getFileState(id).bucket,\n key: handler.getThirdPartyFileId(id),\n accessKey: credentialsProvider.get().accessKey,\n sessionToken: credentialsProvider.get().sessionToken,\n acl: aclStore.get(id),\n minFileSize: validation.minSizeLimit,\n maxFileSize: validation.maxSizeLimit,\n successRedirectUrl: successRedirectUrl,\n reducedRedundancy: reducedRedundancy,\n region: region,\n serverSideEncryption: serverSideEncryption,\n signatureVersion: signature.version,\n log: log\n },\n qq.bind(getSignatureAjaxRequester.getSignature, this, id));\n }\n\n /**\n * Creates form, that will be submitted to iframe\n */\n function createForm(id, iframe) {\n var promise = new qq.Promise(),\n method = \"POST\",\n endpoint = options.endpointStore.get(id),\n fileName = getName(id);\n\n generateAwsParams(id).then(function(params) {\n var form = handler._initFormForUpload({\n method: method,\n endpoint: endpoint,\n params: params,\n paramsInBody: true,\n targetName: iframe.name\n });\n\n promise.success(form);\n }, function(errorMessage) {\n promise.failure(errorMessage);\n handleFinishedUpload(id, iframe, fileName, {error: errorMessage});\n });\n\n return promise;\n }\n\n function handleUpload(id) {\n var iframe = handler._createIframe(id),\n input = handler.getInput(id),\n promise = new qq.Promise();\n\n createForm(id, iframe).then(function(form) {\n form.appendChild(input);\n\n // Register a callback when the response comes in from S3\n handler._attachLoadEvent(iframe, function(response) {\n log(\"iframe loaded\");\n\n // If the common response handler has determined success or failure immediately\n if (response) {\n // If there is something fundamentally wrong with the response (such as iframe content is not accessible)\n if (response.success === false) {\n log(\"Amazon likely rejected the upload request\", \"error\");\n promise.failure(response);\n }\n }\n // The generic response (iframe onload) handler was not able to make a determination regarding the success of the request\n else {\n response = {};\n response.success = isValidResponse(id, iframe);\n\n // If the more specific response handle detected a problem with the response from S3\n if (response.success === false) {\n log(\"A success response was received by Amazon, but it was invalid in some way.\", \"error\");\n promise.failure(response);\n }\n else {\n qq.extend(response, qq.s3.util.parseIframeResponse(iframe));\n promise.success(response);\n }\n }\n\n handleFinishedUpload(id, iframe);\n });\n\n log(\"Sending upload request for \" + id);\n form.submit();\n qq(form).remove();\n }, promise.failure);\n\n return promise;\n }\n\n function handleFinishedUpload(id, iframe) {\n handler._detachLoadEvent(id);\n iframe && qq(iframe).remove();\n }\n\n qq.extend(this, new qq.FormUploadHandler({\n options: {\n isCors: false,\n inputName: \"file\"\n },\n\n proxy: {\n onCancel: options.onCancel,\n onUuidChanged: onUuidChanged,\n getName: getName,\n getUuid: getUuid,\n log: log\n }\n }));\n\n qq.extend(this, {\n uploadFile: function(id) {\n var name = getName(id),\n promise = new qq.Promise();\n\n if (handler.getThirdPartyFileId(id)) {\n if (handler._getFileState(id).bucket) {\n handleUpload(id).then(promise.success, promise.failure);\n }\n else {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n handleUpload(id).then(promise.success, promise.failure);\n });\n }\n }\n else {\n // The S3 uploader module will either calculate the key or ask the server for it\n // and will call us back once it is known.\n onGetKeyName(id, name).then(function(key) {\n onGetBucket(id).then(function(bucket) {\n handler._getFileState(id).bucket = bucket;\n handler._setThirdPartyFileId(id, key);\n handleUpload(id).then(promise.success, promise.failure);\n }, function(errorReason) {\n promise.failure({error: errorReason});\n });\n }, function(errorReason) {\n promise.failure({error: errorReason});\n });\n }\n\n return promise;\n }\n });\n};\n","/*globals qq */\n/**\n * This defines FineUploader mode w/ support for uploading to S3, which provides all the basic\n * functionality of Fine Uploader as well as code to handle uploads directly to S3.\n * This module inherits all logic from FineUploader mode and FineUploaderBasicS3 mode and adds some UI-related logic\n * specific to the upload-to-S3 workflow. Some inherited options and API methods have a special meaning\n * in the context of the S3 uploader.\n */\n(function() {\n \"use strict\";\n\n qq.s3.FineUploader = function(o) {\n var options = {\n failedUploadTextDisplay: {\n mode: \"custom\"\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Inherit instance data from FineUploader, which should in turn inherit from s3.FineUploaderBasic.\n qq.FineUploader.call(this, options, \"s3\");\n\n if (!qq.supportedFeatures.ajaxUploading && options.iframeSupport.localBlankPagePath === undefined) {\n this._options.element.innerHTML = \"You MUST set the localBlankPagePath
property \" +\n \"of the iframeSupport
option since this browser does not support the File API!
\";\n }\n };\n\n // Inherit the API methods from FineUploaderBasicS3\n qq.extend(qq.s3.FineUploader.prototype, qq.s3.FineUploaderBasic.prototype);\n\n // Inherit public and private API methods related to UI\n qq.extend(qq.s3.FineUploader.prototype, qq.uiPublicApi);\n qq.extend(qq.s3.FineUploader.prototype, qq.uiPrivateApi);\n}());\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n","/*globals qq */\n/**\n * This defines FineUploader mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader as well as code to handle uploads directly to Azure.\n * This module inherits all logic from UI & core mode and adds some UI-related logic\n * specific to the upload-to-Azure workflow. Some inherited options and API methods have a special meaning\n * in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploader = function(o) {\n var options = {\n failedUploadTextDisplay: {\n mode: \"custom\"\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Inherit instance data from FineUploader, which should in turn inherit from azure.FineUploaderBasic.\n qq.FineUploader.call(this, options, \"azure\");\n };\n\n // Inherit the API methods from FineUploaderBasicS3\n qq.extend(qq.azure.FineUploader.prototype, qq.azure.FineUploaderBasic.prototype);\n\n // Inherit public and private API methods related to UI\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPublicApi);\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploader.prototype, {\n });\n}());\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.js b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.js
new file mode 100644
index 000000000000..0c3c7ec1ad33
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.js
@@ -0,0 +1,6015 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+(function(global) {
+ var qq = function(element) {
+ "use strict";
+ return {
+ hide: function() {
+ element.style.display = "none";
+ return this;
+ },
+ attach: function(type, fn) {
+ if (element.addEventListener) {
+ element.addEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.attachEvent("on" + type, fn);
+ }
+ return function() {
+ qq(element).detach(type, fn);
+ };
+ },
+ detach: function(type, fn) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.detachEvent("on" + type, fn);
+ }
+ return this;
+ },
+ contains: function(descendant) {
+ if (!descendant) {
+ return false;
+ }
+ if (element === descendant) {
+ return true;
+ }
+ if (element.contains) {
+ return element.contains(descendant);
+ } else {
+ return !!(descendant.compareDocumentPosition(element) & 8);
+ }
+ },
+ insertBefore: function(elementB) {
+ elementB.parentNode.insertBefore(element, elementB);
+ return this;
+ },
+ remove: function() {
+ element.parentNode.removeChild(element);
+ return this;
+ },
+ css: function(styles) {
+ if (element.style == null) {
+ throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");
+ }
+ if (styles.opacity != null) {
+ if (typeof element.style.opacity !== "string" && typeof element.filters !== "undefined") {
+ styles.filter = "alpha(opacity=" + Math.round(100 * styles.opacity) + ")";
+ }
+ }
+ qq.extend(element.style, styles);
+ return this;
+ },
+ hasClass: function(name, considerParent) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));
+ },
+ addClass: function(name) {
+ if (!qq(element).hasClass(name)) {
+ element.className += " " + name;
+ }
+ return this;
+ },
+ removeClass: function(name) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ element.className = element.className.replace(re, " ").replace(/^\s+|\s+$/g, "");
+ return this;
+ },
+ getByClass: function(className, first) {
+ var candidates, result = [];
+ if (first && element.querySelector) {
+ return element.querySelector("." + className);
+ } else if (element.querySelectorAll) {
+ return element.querySelectorAll("." + className);
+ }
+ candidates = element.getElementsByTagName("*");
+ qq.each(candidates, function(idx, val) {
+ if (qq(val).hasClass(className)) {
+ result.push(val);
+ }
+ });
+ return first ? result[0] : result;
+ },
+ getFirstByClass: function(className) {
+ return qq(element).getByClass(className, true);
+ },
+ children: function() {
+ var children = [], child = element.firstChild;
+ while (child) {
+ if (child.nodeType === 1) {
+ children.push(child);
+ }
+ child = child.nextSibling;
+ }
+ return children;
+ },
+ setText: function(text) {
+ element.innerText = text;
+ element.textContent = text;
+ return this;
+ },
+ clearText: function() {
+ return qq(element).setText("");
+ },
+ hasAttribute: function(attrName) {
+ var attrVal;
+ if (element.hasAttribute) {
+ if (!element.hasAttribute(attrName)) {
+ return false;
+ }
+ return /^false$/i.exec(element.getAttribute(attrName)) == null;
+ } else {
+ attrVal = element[attrName];
+ if (attrVal === undefined) {
+ return false;
+ }
+ return /^false$/i.exec(attrVal) == null;
+ }
+ }
+ };
+ };
+ (function() {
+ "use strict";
+ qq.canvasToBlob = function(canvas, mime, quality) {
+ return qq.dataUriToBlob(canvas.toDataURL(mime, quality));
+ };
+ qq.dataUriToBlob = function(dataUri) {
+ var arrayBuffer, byteString, createBlob = function(data, mime) {
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }, intArray, mimeString;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return createBlob(arrayBuffer, mimeString);
+ };
+ qq.log = function(message, level) {
+ if (window.console) {
+ if (!level || level === "info") {
+ window.console.log(message);
+ } else {
+ if (window.console[level]) {
+ window.console[level](message);
+ } else {
+ window.console.log("<" + level + "> " + message);
+ }
+ }
+ }
+ };
+ qq.isObject = function(variable) {
+ return variable && !variable.nodeType && Object.prototype.toString.call(variable) === "[object Object]";
+ };
+ qq.isFunction = function(variable) {
+ return typeof variable === "function";
+ };
+ qq.isArray = function(value) {
+ return Object.prototype.toString.call(value) === "[object Array]" || value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer;
+ };
+ qq.isItemList = function(maybeItemList) {
+ return Object.prototype.toString.call(maybeItemList) === "[object DataTransferItemList]";
+ };
+ qq.isNodeList = function(maybeNodeList) {
+ return Object.prototype.toString.call(maybeNodeList) === "[object NodeList]" || maybeNodeList.item && maybeNodeList.namedItem;
+ };
+ qq.isString = function(maybeString) {
+ return Object.prototype.toString.call(maybeString) === "[object String]";
+ };
+ qq.trimStr = function(string) {
+ if (String.prototype.trim) {
+ return string.trim();
+ }
+ return string.replace(/^\s+|\s+$/g, "");
+ };
+ qq.format = function(str) {
+ var args = Array.prototype.slice.call(arguments, 1), newStr = str, nextIdxToReplace = newStr.indexOf("{}");
+ qq.each(args, function(idx, val) {
+ var strBefore = newStr.substring(0, nextIdxToReplace), strAfter = newStr.substring(nextIdxToReplace + 2);
+ newStr = strBefore + val + strAfter;
+ nextIdxToReplace = newStr.indexOf("{}", nextIdxToReplace + val.length);
+ if (nextIdxToReplace < 0) {
+ return false;
+ }
+ });
+ return newStr;
+ };
+ qq.isFile = function(maybeFile) {
+ return window.File && Object.prototype.toString.call(maybeFile) === "[object File]";
+ };
+ qq.isFileList = function(maybeFileList) {
+ return window.FileList && Object.prototype.toString.call(maybeFileList) === "[object FileList]";
+ };
+ qq.isFileOrInput = function(maybeFileOrInput) {
+ return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);
+ };
+ qq.isInput = function(maybeInput, notFile) {
+ var evaluateType = function(type) {
+ var normalizedType = type.toLowerCase();
+ if (notFile) {
+ return normalizedType !== "file";
+ }
+ return normalizedType === "file";
+ };
+ if (window.HTMLInputElement) {
+ if (Object.prototype.toString.call(maybeInput) === "[object HTMLInputElement]") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ if (maybeInput.tagName) {
+ if (maybeInput.tagName.toLowerCase() === "input") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ qq.isBlob = function(maybeBlob) {
+ if (window.Blob && Object.prototype.toString.call(maybeBlob) === "[object Blob]") {
+ return true;
+ }
+ };
+ qq.isXhrUploadSupported = function() {
+ var input = document.createElement("input");
+ input.type = "file";
+ return input.multiple !== undefined && typeof File !== "undefined" && typeof FormData !== "undefined" && typeof qq.createXhrInstance().upload !== "undefined";
+ };
+ qq.createXhrInstance = function() {
+ if (window.XMLHttpRequest) {
+ return new XMLHttpRequest();
+ }
+ try {
+ return new ActiveXObject("MSXML2.XMLHTTP.3.0");
+ } catch (error) {
+ qq.log("Neither XHR or ActiveX are supported!", "error");
+ return null;
+ }
+ };
+ qq.isFolderDropSupported = function(dataTransfer) {
+ return dataTransfer.items && dataTransfer.items.length > 0 && dataTransfer.items[0].webkitGetAsEntry;
+ };
+ qq.isFileChunkingSupported = function() {
+ return !qq.androidStock() && qq.isXhrUploadSupported() && (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);
+ };
+ qq.sliceBlob = function(fileOrBlob, start, end) {
+ var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;
+ return slicer.call(fileOrBlob, start, end);
+ };
+ qq.arrayBufferToHex = function(buffer) {
+ var bytesAsHex = "", bytes = new Uint8Array(buffer);
+ qq.each(bytes, function(idx, byt) {
+ var byteAsHexStr = byt.toString(16);
+ if (byteAsHexStr.length < 2) {
+ byteAsHexStr = "0" + byteAsHexStr;
+ }
+ bytesAsHex += byteAsHexStr;
+ });
+ return bytesAsHex;
+ };
+ qq.readBlobToHex = function(blob, startOffset, length) {
+ var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), fileReader = new FileReader(), promise = new qq.Promise();
+ fileReader.onload = function() {
+ promise.success(qq.arrayBufferToHex(fileReader.result));
+ };
+ fileReader.onerror = promise.failure;
+ fileReader.readAsArrayBuffer(initialBlob);
+ return promise;
+ };
+ qq.extend = function(first, second, extendNested) {
+ qq.each(second, function(prop, val) {
+ if (extendNested && qq.isObject(val)) {
+ if (first[prop] === undefined) {
+ first[prop] = {};
+ }
+ qq.extend(first[prop], val, true);
+ } else {
+ first[prop] = val;
+ }
+ });
+ return first;
+ };
+ qq.override = function(target, sourceFn) {
+ var super_ = {}, source = sourceFn(super_);
+ qq.each(source, function(srcPropName, srcPropVal) {
+ if (target[srcPropName] !== undefined) {
+ super_[srcPropName] = target[srcPropName];
+ }
+ target[srcPropName] = srcPropVal;
+ });
+ return target;
+ };
+ qq.indexOf = function(arr, elt, from) {
+ if (arr.indexOf) {
+ return arr.indexOf(elt, from);
+ }
+ from = from || 0;
+ var len = arr.length;
+ if (from < 0) {
+ from += len;
+ }
+ for (;from < len; from += 1) {
+ if (arr.hasOwnProperty(from) && arr[from] === elt) {
+ return from;
+ }
+ }
+ return -1;
+ };
+ qq.getUniqueId = function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
+ return v.toString(16);
+ });
+ };
+ qq.ie = function() {
+ return navigator.userAgent.indexOf("MSIE") !== -1 || navigator.userAgent.indexOf("Trident") !== -1;
+ };
+ qq.ie7 = function() {
+ return navigator.userAgent.indexOf("MSIE 7") !== -1;
+ };
+ qq.ie8 = function() {
+ return navigator.userAgent.indexOf("MSIE 8") !== -1;
+ };
+ qq.ie10 = function() {
+ return navigator.userAgent.indexOf("MSIE 10") !== -1;
+ };
+ qq.ie11 = function() {
+ return qq.ie() && navigator.userAgent.indexOf("rv:11") !== -1;
+ };
+ qq.edge = function() {
+ return navigator.userAgent.indexOf("Edge") >= 0;
+ };
+ qq.safari = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Apple") !== -1;
+ };
+ qq.chrome = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Google") !== -1;
+ };
+ qq.opera = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Opera") !== -1;
+ };
+ qq.firefox = function() {
+ return !qq.edge() && !qq.ie11() && navigator.userAgent.indexOf("Mozilla") !== -1 && navigator.vendor !== undefined && navigator.vendor === "";
+ };
+ qq.windows = function() {
+ return navigator.platform === "Win32";
+ };
+ qq.android = function() {
+ return navigator.userAgent.toLowerCase().indexOf("android") !== -1;
+ };
+ qq.androidStock = function() {
+ return qq.android() && navigator.userAgent.toLowerCase().indexOf("chrome") < 0;
+ };
+ qq.ios6 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 6_") !== -1;
+ };
+ qq.ios7 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 7_") !== -1;
+ };
+ qq.ios8 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_") !== -1;
+ };
+ qq.ios800 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_0 ") !== -1;
+ };
+ qq.ios = function() {
+ return navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("iPod") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1;
+ };
+ qq.iosChrome = function() {
+ return qq.ios() && navigator.userAgent.indexOf("CriOS") !== -1;
+ };
+ qq.iosSafari = function() {
+ return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf("Safari") !== -1;
+ };
+ qq.iosSafariWebView = function() {
+ return qq.ios() && !qq.iosChrome() && !qq.iosSafari();
+ };
+ qq.preventDefault = function(e) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ };
+ qq.toElement = function() {
+ var div = document.createElement("div");
+ return function(html) {
+ div.innerHTML = html;
+ var element = div.firstChild;
+ div.removeChild(element);
+ return element;
+ };
+ }();
+ qq.each = function(iterableItem, callback) {
+ var keyOrIndex, retVal;
+ if (iterableItem) {
+ if (window.Storage && iterableItem.constructor === window.Storage) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isString(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else {
+ for (keyOrIndex in iterableItem) {
+ if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ };
+ qq.bind = function(oldFunc, context) {
+ if (qq.isFunction(oldFunc)) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ return function() {
+ var newArgs = qq.extend([], args);
+ if (arguments.length) {
+ newArgs = newArgs.concat(Array.prototype.slice.call(arguments));
+ }
+ return oldFunc.apply(context, newArgs);
+ };
+ }
+ throw new Error("first parameter must be a function!");
+ };
+ qq.obj2url = function(obj, temp, prefixDone) {
+ var uristrings = [], prefix = "&", add = function(nextObj, i) {
+ var nextTemp = temp ? /\[\]$/.test(temp) ? temp : temp + "[" + i + "]" : i;
+ if (nextTemp !== "undefined" && i !== "undefined") {
+ uristrings.push(typeof nextObj === "object" ? qq.obj2url(nextObj, nextTemp, true) : Object.prototype.toString.call(nextObj) === "[object Function]" ? encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj));
+ }
+ };
+ if (!prefixDone && temp) {
+ prefix = /\?/.test(temp) ? /\?$/.test(temp) ? "" : "&" : "?";
+ uristrings.push(temp);
+ uristrings.push(qq.obj2url(obj));
+ } else if (Object.prototype.toString.call(obj) === "[object Array]" && typeof obj !== "undefined") {
+ qq.each(obj, function(idx, val) {
+ add(val, idx);
+ });
+ } else if (typeof obj !== "undefined" && obj !== null && typeof obj === "object") {
+ qq.each(obj, function(prop, val) {
+ add(val, prop);
+ });
+ } else {
+ uristrings.push(encodeURIComponent(temp) + "=" + encodeURIComponent(obj));
+ }
+ if (temp) {
+ return uristrings.join(prefix);
+ } else {
+ return uristrings.join(prefix).replace(/^&/, "").replace(/%20/g, "+");
+ }
+ };
+ qq.obj2FormData = function(obj, formData, arrayKeyName) {
+ if (!formData) {
+ formData = new FormData();
+ }
+ qq.each(obj, function(key, val) {
+ key = arrayKeyName ? arrayKeyName + "[" + key + "]" : key;
+ if (qq.isObject(val)) {
+ qq.obj2FormData(val, formData, key);
+ } else if (qq.isFunction(val)) {
+ formData.append(key, val());
+ } else {
+ formData.append(key, val);
+ }
+ });
+ return formData;
+ };
+ qq.obj2Inputs = function(obj, form) {
+ var input;
+ if (!form) {
+ form = document.createElement("form");
+ }
+ qq.obj2FormData(obj, {
+ append: function(key, val) {
+ input = document.createElement("input");
+ input.setAttribute("name", key);
+ input.setAttribute("value", val);
+ form.appendChild(input);
+ }
+ });
+ return form;
+ };
+ qq.parseJson = function(json) {
+ if (window.JSON && qq.isFunction(JSON.parse)) {
+ return JSON.parse(json);
+ } else {
+ return eval("(" + json + ")");
+ }
+ };
+ qq.getExtension = function(filename) {
+ var extIdx = filename.lastIndexOf(".") + 1;
+ if (extIdx > 0) {
+ return filename.substr(extIdx, filename.length - extIdx);
+ }
+ };
+ qq.getFilename = function(blobOrFileInput) {
+ if (qq.isInput(blobOrFileInput)) {
+ return blobOrFileInput.value.replace(/.*(\/|\\)/, "");
+ } else if (qq.isFile(blobOrFileInput)) {
+ if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {
+ return blobOrFileInput.fileName;
+ }
+ }
+ return blobOrFileInput.name;
+ };
+ qq.DisposeSupport = function() {
+ var disposers = [];
+ return {
+ dispose: function() {
+ var disposer;
+ do {
+ disposer = disposers.shift();
+ if (disposer) {
+ disposer();
+ }
+ } while (disposer);
+ },
+ attach: function() {
+ var args = arguments;
+ this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));
+ },
+ addDisposer: function(disposeFunction) {
+ disposers.push(disposeFunction);
+ }
+ };
+ };
+ })();
+ (function() {
+ "use strict";
+ if (typeof define === "function" && define.amd) {
+ define(function() {
+ return qq;
+ });
+ } else if (typeof module !== "undefined" && module.exports) {
+ module.exports = qq;
+ } else {
+ global.qq = qq;
+ }
+ })();
+ (function() {
+ "use strict";
+ qq.Error = function(message) {
+ this.message = "[Fine Uploader " + qq.version + "] " + message;
+ };
+ qq.Error.prototype = new Error();
+ })();
+ qq.version = "5.13.0";
+ qq.supportedFeatures = function() {
+ "use strict";
+ var supportsUploading, supportsUploadingBlobs, supportsFileDrop, supportsAjaxFileUploading, supportsFolderDrop, supportsChunking, supportsResume, supportsUploadViaPaste, supportsUploadCors, supportsDeleteFileXdr, supportsDeleteFileCorsXhr, supportsDeleteFileCors, supportsFolderSelection, supportsImagePreviews, supportsUploadProgress;
+ function testSupportsFileInputElement() {
+ var supported = true, tempInput;
+ try {
+ tempInput = document.createElement("input");
+ tempInput.type = "file";
+ qq(tempInput).hide();
+ if (tempInput.disabled) {
+ supported = false;
+ }
+ } catch (ex) {
+ supported = false;
+ }
+ return supported;
+ }
+ function isChrome21OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/) !== undefined;
+ }
+ function isChrome14OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/) !== undefined;
+ }
+ function isCrossOriginXhrSupported() {
+ if (window.XMLHttpRequest) {
+ var xhr = qq.createXhrInstance();
+ return xhr.withCredentials !== undefined;
+ }
+ return false;
+ }
+ function isXdrSupported() {
+ return window.XDomainRequest !== undefined;
+ }
+ function isCrossOriginAjaxSupported() {
+ if (isCrossOriginXhrSupported()) {
+ return true;
+ }
+ return isXdrSupported();
+ }
+ function isFolderSelectionSupported() {
+ return document.createElement("input").webkitdirectory !== undefined;
+ }
+ function isLocalStorageSupported() {
+ try {
+ return !!window.localStorage && qq.isFunction(window.localStorage.setItem);
+ } catch (error) {
+ return false;
+ }
+ }
+ function isDragAndDropSupported() {
+ var span = document.createElement("span");
+ return ("draggable" in span || "ondragstart" in span && "ondrop" in span) && !qq.android() && !qq.ios();
+ }
+ supportsUploading = testSupportsFileInputElement();
+ supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();
+ supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();
+ supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();
+ supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();
+ supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();
+ supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();
+ supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();
+ supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);
+ supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();
+ supportsDeleteFileXdr = isXdrSupported();
+ supportsDeleteFileCors = isCrossOriginAjaxSupported();
+ supportsFolderSelection = isFolderSelectionSupported();
+ supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;
+ supportsUploadProgress = function() {
+ if (supportsAjaxFileUploading) {
+ return !qq.androidStock() && !qq.iosChrome();
+ }
+ return false;
+ }();
+ return {
+ ajaxUploading: supportsAjaxFileUploading,
+ blobUploading: supportsUploadingBlobs,
+ canDetermineSize: supportsAjaxFileUploading,
+ chunking: supportsChunking,
+ deleteFileCors: supportsDeleteFileCors,
+ deleteFileCorsXdr: supportsDeleteFileXdr,
+ deleteFileCorsXhr: supportsDeleteFileCorsXhr,
+ dialogElement: !!window.HTMLDialogElement,
+ fileDrop: supportsFileDrop,
+ folderDrop: supportsFolderDrop,
+ folderSelection: supportsFolderSelection,
+ imagePreviews: supportsImagePreviews,
+ imageValidation: supportsImagePreviews,
+ itemSizeValidation: supportsAjaxFileUploading,
+ pause: supportsChunking,
+ progressBar: supportsUploadProgress,
+ resume: supportsResume,
+ scaling: supportsImagePreviews && supportsUploadingBlobs,
+ tiffPreviews: qq.safari(),
+ unlimitedScaledImageSize: !qq.ios(),
+ uploading: supportsUploading,
+ uploadCors: supportsUploadCors,
+ uploadCustomHeaders: supportsAjaxFileUploading,
+ uploadNonMultipart: supportsAjaxFileUploading,
+ uploadViaPaste: supportsUploadViaPaste
+ };
+ }();
+ qq.isGenericPromise = function(maybePromise) {
+ "use strict";
+ return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));
+ };
+ qq.Promise = function() {
+ "use strict";
+ var successArgs, failureArgs, successCallbacks = [], failureCallbacks = [], doneCallbacks = [], state = 0;
+ qq.extend(this, {
+ then: function(onSuccess, onFailure) {
+ if (state === 0) {
+ if (onSuccess) {
+ successCallbacks.push(onSuccess);
+ }
+ if (onFailure) {
+ failureCallbacks.push(onFailure);
+ }
+ } else if (state === -1) {
+ onFailure && onFailure.apply(null, failureArgs);
+ } else if (onSuccess) {
+ onSuccess.apply(null, successArgs);
+ }
+ return this;
+ },
+ done: function(callback) {
+ if (state === 0) {
+ doneCallbacks.push(callback);
+ } else {
+ callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);
+ }
+ return this;
+ },
+ success: function() {
+ state = 1;
+ successArgs = arguments;
+ if (successCallbacks.length) {
+ qq.each(successCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ return this;
+ },
+ failure: function() {
+ state = -1;
+ failureArgs = arguments;
+ if (failureCallbacks.length) {
+ qq.each(failureCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ return this;
+ }
+ });
+ };
+ qq.BlobProxy = function(referenceBlob, onCreate) {
+ "use strict";
+ qq.extend(this, {
+ referenceBlob: referenceBlob,
+ create: function() {
+ return onCreate(referenceBlob);
+ }
+ });
+ };
+ qq.UploadButton = function(o) {
+ "use strict";
+ var self = this, disposeSupport = new qq.DisposeSupport(), options = {
+ acceptFiles: null,
+ element: null,
+ focusClass: "qq-upload-button-focus",
+ folders: false,
+ hoverClass: "qq-upload-button-hover",
+ ios8BrowserCrashWorkaround: false,
+ multiple: false,
+ name: "qqfile",
+ onChange: function(input) {},
+ title: null
+ }, input, buttonId;
+ qq.extend(options, o);
+ buttonId = qq.getUniqueId();
+ function createInput() {
+ var input = document.createElement("input");
+ input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);
+ input.setAttribute("title", options.title);
+ self.setMultiple(options.multiple, input);
+ if (options.folders && qq.supportedFeatures.folderSelection) {
+ input.setAttribute("webkitdirectory", "");
+ }
+ if (options.acceptFiles) {
+ input.setAttribute("accept", options.acceptFiles);
+ }
+ input.setAttribute("type", "file");
+ input.setAttribute("name", options.name);
+ qq(input).css({
+ position: "absolute",
+ right: 0,
+ top: 0,
+ fontFamily: "Arial",
+ fontSize: qq.ie() && !qq.ie8() ? "3500px" : "118px",
+ margin: 0,
+ padding: 0,
+ cursor: "pointer",
+ opacity: 0
+ });
+ !qq.ie7() && qq(input).css({
+ height: "100%"
+ });
+ options.element.appendChild(input);
+ disposeSupport.attach(input, "change", function() {
+ options.onChange(input);
+ });
+ disposeSupport.attach(input, "mouseover", function() {
+ qq(options.element).addClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "mouseout", function() {
+ qq(options.element).removeClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "focus", function() {
+ qq(options.element).addClass(options.focusClass);
+ });
+ disposeSupport.attach(input, "blur", function() {
+ qq(options.element).removeClass(options.focusClass);
+ });
+ return input;
+ }
+ qq(options.element).css({
+ position: "relative",
+ overflow: "hidden",
+ direction: "ltr"
+ });
+ qq.extend(this, {
+ getInput: function() {
+ return input;
+ },
+ getButtonId: function() {
+ return buttonId;
+ },
+ setMultiple: function(isMultiple, optInput) {
+ var input = optInput || this.getInput();
+ if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {
+ input.setAttribute("multiple", "");
+ } else {
+ if (isMultiple) {
+ input.setAttribute("multiple", "");
+ } else {
+ input.removeAttribute("multiple");
+ }
+ }
+ },
+ setAcceptFiles: function(acceptFiles) {
+ if (acceptFiles !== options.acceptFiles) {
+ input.setAttribute("accept", acceptFiles);
+ }
+ },
+ reset: function() {
+ if (input.parentNode) {
+ qq(input).remove();
+ }
+ qq(options.element).removeClass(options.focusClass);
+ input = null;
+ input = createInput();
+ }
+ });
+ input = createInput();
+ };
+ qq.UploadButton.BUTTON_ID_ATTR_NAME = "qq-button-id";
+ qq.UploadData = function(uploaderProxy) {
+ "use strict";
+ var data = [], byUuid = {}, byStatus = {}, byProxyGroupId = {}, byBatchId = {};
+ function getDataByIds(idOrIds) {
+ if (qq.isArray(idOrIds)) {
+ var entries = [];
+ qq.each(idOrIds, function(idx, id) {
+ entries.push(data[id]);
+ });
+ return entries;
+ }
+ return data[idOrIds];
+ }
+ function getDataByUuids(uuids) {
+ if (qq.isArray(uuids)) {
+ var entries = [];
+ qq.each(uuids, function(idx, uuid) {
+ entries.push(data[byUuid[uuid]]);
+ });
+ return entries;
+ }
+ return data[byUuid[uuids]];
+ }
+ function getDataByStatus(status) {
+ var statusResults = [], statuses = [].concat(status);
+ qq.each(statuses, function(index, statusEnum) {
+ var statusResultIndexes = byStatus[statusEnum];
+ if (statusResultIndexes !== undefined) {
+ qq.each(statusResultIndexes, function(i, dataIndex) {
+ statusResults.push(data[dataIndex]);
+ });
+ }
+ });
+ return statusResults;
+ }
+ qq.extend(this, {
+ addFile: function(spec) {
+ var status = spec.status || qq.status.SUBMITTING, id = data.push({
+ name: spec.name,
+ originalName: spec.name,
+ uuid: spec.uuid,
+ size: spec.size == null ? -1 : spec.size,
+ status: status
+ }) - 1;
+ if (spec.batchId) {
+ data[id].batchId = spec.batchId;
+ if (byBatchId[spec.batchId] === undefined) {
+ byBatchId[spec.batchId] = [];
+ }
+ byBatchId[spec.batchId].push(id);
+ }
+ if (spec.proxyGroupId) {
+ data[id].proxyGroupId = spec.proxyGroupId;
+ if (byProxyGroupId[spec.proxyGroupId] === undefined) {
+ byProxyGroupId[spec.proxyGroupId] = [];
+ }
+ byProxyGroupId[spec.proxyGroupId].push(id);
+ }
+ data[id].id = id;
+ byUuid[spec.uuid] = id;
+ if (byStatus[status] === undefined) {
+ byStatus[status] = [];
+ }
+ byStatus[status].push(id);
+ uploaderProxy.onStatusChange(id, null, status);
+ return id;
+ },
+ retrieve: function(optionalFilter) {
+ if (qq.isObject(optionalFilter) && data.length) {
+ if (optionalFilter.id !== undefined) {
+ return getDataByIds(optionalFilter.id);
+ } else if (optionalFilter.uuid !== undefined) {
+ return getDataByUuids(optionalFilter.uuid);
+ } else if (optionalFilter.status) {
+ return getDataByStatus(optionalFilter.status);
+ }
+ } else {
+ return qq.extend([], data, true);
+ }
+ },
+ reset: function() {
+ data = [];
+ byUuid = {};
+ byStatus = {};
+ byBatchId = {};
+ },
+ setStatus: function(id, newStatus) {
+ var oldStatus = data[id].status, byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);
+ byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);
+ data[id].status = newStatus;
+ if (byStatus[newStatus] === undefined) {
+ byStatus[newStatus] = [];
+ }
+ byStatus[newStatus].push(id);
+ uploaderProxy.onStatusChange(id, oldStatus, newStatus);
+ },
+ uuidChanged: function(id, newUuid) {
+ var oldUuid = data[id].uuid;
+ data[id].uuid = newUuid;
+ byUuid[newUuid] = id;
+ delete byUuid[oldUuid];
+ },
+ updateName: function(id, newName) {
+ data[id].name = newName;
+ },
+ updateSize: function(id, newSize) {
+ data[id].size = newSize;
+ },
+ setParentId: function(targetId, parentId) {
+ data[targetId].parentId = parentId;
+ },
+ getIdsInProxyGroup: function(id) {
+ var proxyGroupId = data[id].proxyGroupId;
+ if (proxyGroupId) {
+ return byProxyGroupId[proxyGroupId];
+ }
+ return [];
+ },
+ getIdsInBatch: function(id) {
+ var batchId = data[id].batchId;
+ return byBatchId[batchId];
+ }
+ });
+ };
+ qq.status = {
+ SUBMITTING: "submitting",
+ SUBMITTED: "submitted",
+ REJECTED: "rejected",
+ QUEUED: "queued",
+ CANCELED: "canceled",
+ PAUSED: "paused",
+ UPLOADING: "uploading",
+ UPLOAD_RETRYING: "retrying upload",
+ UPLOAD_SUCCESSFUL: "upload successful",
+ UPLOAD_FAILED: "upload failed",
+ DELETE_FAILED: "delete failed",
+ DELETING: "deleting",
+ DELETED: "deleted"
+ };
+ (function() {
+ "use strict";
+ qq.basePublicApi = {
+ addBlobs: function(blobDataOrArray, params, endpoint) {
+ this.addFiles(blobDataOrArray, params, endpoint);
+ },
+ addInitialFiles: function(cannedFileList) {
+ var self = this;
+ qq.each(cannedFileList, function(index, cannedFile) {
+ self._addCannedFile(cannedFile);
+ });
+ },
+ addFiles: function(data, params, endpoint) {
+ this._maybeHandleIos8SafariWorkaround();
+ var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId, processBlob = qq.bind(function(blob) {
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName
+ }, batchId, verifiedFiles);
+ }, this), processBlobData = qq.bind(function(blobData) {
+ this._handleNewFile(blobData, batchId, verifiedFiles);
+ }, this), processCanvas = qq.bind(function(canvas) {
+ var blob = qq.canvasToBlob(canvas);
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName + ".png"
+ }, batchId, verifiedFiles);
+ }, this), processCanvasData = qq.bind(function(canvasData) {
+ var normalizedQuality = canvasData.quality && canvasData.quality / 100, blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);
+ this._handleNewFile({
+ blob: blob,
+ name: canvasData.name
+ }, batchId, verifiedFiles);
+ }, this), processFileOrInput = qq.bind(function(fileOrInput) {
+ if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {
+ var files = Array.prototype.slice.call(fileOrInput.files), self = this;
+ qq.each(files, function(idx, file) {
+ self._handleNewFile(file, batchId, verifiedFiles);
+ });
+ } else {
+ this._handleNewFile(fileOrInput, batchId, verifiedFiles);
+ }
+ }, this), normalizeData = function() {
+ if (qq.isFileList(data)) {
+ data = Array.prototype.slice.call(data);
+ }
+ data = [].concat(data);
+ }, self = this, verifiedFiles = [];
+ this._currentBatchId = batchId;
+ if (data) {
+ normalizeData();
+ qq.each(data, function(idx, fileContainer) {
+ if (qq.isFileOrInput(fileContainer)) {
+ processFileOrInput(fileContainer);
+ } else if (qq.isBlob(fileContainer)) {
+ processBlob(fileContainer);
+ } else if (qq.isObject(fileContainer)) {
+ if (fileContainer.blob && fileContainer.name) {
+ processBlobData(fileContainer);
+ } else if (fileContainer.canvas && fileContainer.name) {
+ processCanvasData(fileContainer);
+ }
+ } else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === "canvas") {
+ processCanvas(fileContainer);
+ } else {
+ self.log(fileContainer + " is not a valid file container! Ignoring!", "warn");
+ }
+ });
+ this.log("Received " + verifiedFiles.length + " files.");
+ this._prepareItemsForUpload(verifiedFiles, params, endpoint);
+ }
+ },
+ cancel: function(id) {
+ this._handler.cancel(id);
+ },
+ cancelAll: function() {
+ var storedIdsCopy = [], self = this;
+ qq.extend(storedIdsCopy, this._storedIds);
+ qq.each(storedIdsCopy, function(idx, storedFileId) {
+ self.cancel(storedFileId);
+ });
+ this._handler.cancelAll();
+ },
+ clearStoredFiles: function() {
+ this._storedIds = [];
+ },
+ continueUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (uploadData.status === qq.status.PAUSED) {
+ this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.", id, this.getName(id)));
+ this._uploadFile(id);
+ return true;
+ } else {
+ this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ deleteFile: function(id) {
+ return this._onSubmitDelete(id);
+ },
+ doesExist: function(fileOrBlobId) {
+ return this._handler.isValid(fileOrBlobId);
+ },
+ drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {
+ var promiseToReturn = new qq.Promise(), fileOrUrl, options;
+ if (this._imageGenerator) {
+ fileOrUrl = this._thumbnailUrls[fileId];
+ options = {
+ customResizeFunction: customResizeFunction,
+ maxSize: maxSize > 0 ? maxSize : null,
+ scale: maxSize > 0
+ };
+ if (!fromServer && qq.supportedFeatures.imagePreviews) {
+ fileOrUrl = this.getFile(fileId);
+ }
+ if (fileOrUrl == null) {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "File or URL not found."
+ });
+ } else {
+ this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(function success(modifiedContainer) {
+ promiseToReturn.success(modifiedContainer);
+ }, function failure(container, reason) {
+ promiseToReturn.failure({
+ container: container,
+ error: reason || "Problem generating thumbnail"
+ });
+ });
+ }
+ } else {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "Missing image generator module"
+ });
+ }
+ return promiseToReturn;
+ },
+ getButton: function(fileId) {
+ return this._getButton(this._buttonIdsForFileIds[fileId]);
+ },
+ getEndpoint: function(fileId) {
+ return this._endpointStore.get(fileId);
+ },
+ getFile: function(fileOrBlobId) {
+ return this._handler.getFile(fileOrBlobId) || null;
+ },
+ getInProgress: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED ]
+ }).length;
+ },
+ getName: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).name;
+ },
+ getParentId: function(id) {
+ var uploadDataEntry = this.getUploads({
+ id: id
+ }), parentId = null;
+ if (uploadDataEntry) {
+ if (uploadDataEntry.parentId !== undefined) {
+ parentId = uploadDataEntry.parentId;
+ }
+ }
+ return parentId;
+ },
+ getResumableFilesData: function() {
+ return this._handler.getResumableFilesData();
+ },
+ getSize: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).size;
+ },
+ getNetUploads: function() {
+ return this._netUploaded;
+ },
+ getRemainingAllowedItems: function() {
+ var allowedItems = this._currentItemLimit;
+ if (allowedItems > 0) {
+ return allowedItems - this._netUploadedOrQueued;
+ }
+ return null;
+ },
+ getUploads: function(optionalFilter) {
+ return this._uploadData.retrieve(optionalFilter);
+ },
+ getUuid: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).uuid;
+ },
+ log: function(str, level) {
+ if (this._options.debug && (!level || level === "info")) {
+ qq.log("[Fine Uploader " + qq.version + "] " + str);
+ } else if (level && level !== "info") {
+ qq.log("[Fine Uploader " + qq.version + "] " + str, level);
+ }
+ },
+ pauseUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (qq.indexOf([ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING ], uploadData.status) >= 0) {
+ if (this._handler.pause(id)) {
+ this._uploadData.setStatus(id, qq.status.PAUSED);
+ return true;
+ } else {
+ this.log(qq.format("Unable to pause file ID {} ({}).", id, this.getName(id)), "error");
+ }
+ } else {
+ this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ reset: function() {
+ this.log("Resetting uploader...");
+ this._handler.reset();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ this._paramsStore.reset();
+ this._endpointStore.reset();
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData.reset();
+ this._buttonIdsForFileIds = [];
+ this._pasteHandler && this._pasteHandler.reset();
+ this._options.session.refreshOnReset && this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._totalProgress && this._totalProgress.reset();
+ },
+ retry: function(id) {
+ return this._manualRetry(id);
+ },
+ scaleImage: function(id, specs) {
+ var self = this;
+ return qq.Scaler.prototype.scaleImage(id, specs, {
+ log: qq.bind(self.log, self),
+ getFile: qq.bind(self.getFile, self),
+ uploadData: self._uploadData
+ });
+ },
+ setCustomHeaders: function(headers, id) {
+ this._customHeadersStore.set(headers, id);
+ },
+ setDeleteFileCustomHeaders: function(headers, id) {
+ this._deleteFileCustomHeadersStore.set(headers, id);
+ },
+ setDeleteFileEndpoint: function(endpoint, id) {
+ this._deleteFileEndpointStore.set(endpoint, id);
+ },
+ setDeleteFileParams: function(params, id) {
+ this._deleteFileParamsStore.set(params, id);
+ },
+ setEndpoint: function(endpoint, id) {
+ this._endpointStore.set(endpoint, id);
+ },
+ setForm: function(elementOrId) {
+ this._updateFormSupportAndParams(elementOrId);
+ },
+ setItemLimit: function(newItemLimit) {
+ this._currentItemLimit = newItemLimit;
+ },
+ setName: function(id, newName) {
+ this._uploadData.updateName(id, newName);
+ },
+ setParams: function(params, id) {
+ this._paramsStore.set(params, id);
+ },
+ setUuid: function(id, newUuid) {
+ return this._uploadData.uuidChanged(id, newUuid);
+ },
+ uploadStoredFiles: function() {
+ if (this._storedIds.length === 0) {
+ this._itemError("noFilesError");
+ } else {
+ this._uploadStoredFiles();
+ }
+ }
+ };
+ qq.basePrivateApi = {
+ _addCannedFile: function(sessionData) {
+ var id = this._uploadData.addFile({
+ uuid: sessionData.uuid,
+ name: sessionData.name,
+ size: sessionData.size,
+ status: qq.status.UPLOAD_SUCCESSFUL
+ });
+ sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);
+ sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);
+ if (sessionData.thumbnailUrl) {
+ this._thumbnailUrls[id] = sessionData.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._netUploadedOrQueued++;
+ return id;
+ },
+ _annotateWithButtonId: function(file, associatedInput) {
+ if (qq.isFile(file)) {
+ file.qqButtonId = this._getButtonId(associatedInput);
+ }
+ },
+ _batchError: function(message) {
+ this._options.callbacks.onError(null, null, message, undefined);
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return new qq.DeleteFileAjaxRequester({
+ method: this._options.deleteFile.method.toUpperCase(),
+ maxConnections: this._options.maxConnections,
+ uuidParamName: this._options.request.uuidName,
+ customHeaders: this._deleteFileCustomHeadersStore,
+ paramsStore: this._deleteFileParamsStore,
+ endpointStore: this._deleteFileEndpointStore,
+ cors: this._options.cors,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ });
+ },
+ _createPasteHandler: function() {
+ var self = this;
+ return new qq.PasteSupport({
+ targetElement: this._options.paste.targetElement,
+ callbacks: {
+ log: qq.bind(self.log, self),
+ pasteReceived: function(blob) {
+ self._handleCheckedCallback({
+ name: "onPasteReceived",
+ callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),
+ onSuccess: qq.bind(self._handlePasteSuccess, self, blob),
+ identifier: "pasted image"
+ });
+ }
+ }
+ });
+ },
+ _createStore: function(initialValue, _readOnlyValues_) {
+ var store = {}, catchall = initialValue, perIdReadOnlyValues = {}, readOnlyValues = _readOnlyValues_, copy = function(orig) {
+ if (qq.isObject(orig)) {
+ return qq.extend({}, orig);
+ }
+ return orig;
+ }, getReadOnlyValues = function() {
+ if (qq.isFunction(readOnlyValues)) {
+ return readOnlyValues();
+ }
+ return readOnlyValues;
+ }, includeReadOnlyValues = function(id, existing) {
+ if (readOnlyValues && qq.isObject(existing)) {
+ qq.extend(existing, getReadOnlyValues());
+ }
+ if (perIdReadOnlyValues[id]) {
+ qq.extend(existing, perIdReadOnlyValues[id]);
+ }
+ };
+ return {
+ set: function(val, id) {
+ if (id == null) {
+ store = {};
+ catchall = copy(val);
+ } else {
+ store[id] = copy(val);
+ }
+ },
+ get: function(id) {
+ var values;
+ if (id != null && store[id]) {
+ values = store[id];
+ } else {
+ values = copy(catchall);
+ }
+ includeReadOnlyValues(id, values);
+ return copy(values);
+ },
+ addReadOnly: function(id, values) {
+ if (qq.isObject(store)) {
+ if (id === null) {
+ if (qq.isFunction(values)) {
+ readOnlyValues = values;
+ } else {
+ readOnlyValues = readOnlyValues || {};
+ qq.extend(readOnlyValues, values);
+ }
+ } else {
+ perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};
+ qq.extend(perIdReadOnlyValues[id], values);
+ }
+ }
+ },
+ remove: function(fileId) {
+ return delete store[fileId];
+ },
+ reset: function() {
+ store = {};
+ perIdReadOnlyValues = {};
+ catchall = initialValue;
+ }
+ };
+ },
+ _createUploadDataTracker: function() {
+ var self = this;
+ return new qq.UploadData({
+ getName: function(id) {
+ return self.getName(id);
+ },
+ getUuid: function(id) {
+ return self.getUuid(id);
+ },
+ getSize: function(id) {
+ return self.getSize(id);
+ },
+ onStatusChange: function(id, oldStatus, newStatus) {
+ self._onUploadStatusChange(id, oldStatus, newStatus);
+ self._options.callbacks.onStatusChange(id, oldStatus, newStatus);
+ self._maybeAllComplete(id, newStatus);
+ if (self._totalProgress) {
+ setTimeout(function() {
+ self._totalProgress.onStatusChange(id, oldStatus, newStatus);
+ }, 0);
+ }
+ }
+ });
+ },
+ _createUploadButton: function(spec) {
+ var self = this, acceptFiles = spec.accept || this._options.validation.acceptFiles, allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions, button;
+ function allowMultiple() {
+ if (qq.supportedFeatures.ajaxUploading) {
+ if (self._options.workarounds.iosEmptyVideos && qq.ios() && !qq.ios6() && self._isAllowedExtension(allowedExtensions, ".mov")) {
+ return false;
+ }
+ if (spec.multiple === undefined) {
+ return self._options.multiple;
+ }
+ return spec.multiple;
+ }
+ return false;
+ }
+ button = new qq.UploadButton({
+ acceptFiles: acceptFiles,
+ element: spec.element,
+ focusClass: this._options.classes.buttonFocus,
+ folders: spec.folders,
+ hoverClass: this._options.classes.buttonHover,
+ ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,
+ multiple: allowMultiple(),
+ name: this._options.request.inputName,
+ onChange: function(input) {
+ self._onInputChange(input);
+ },
+ title: spec.title == null ? this._options.text.fileInputTitle : spec.title
+ });
+ this._disposeSupport.addDisposer(function() {
+ button.dispose();
+ });
+ self._buttons.push(button);
+ return button;
+ },
+ _createUploadHandler: function(additionalOptions, namespace) {
+ var self = this, lastOnProgress = {}, options = {
+ debug: this._options.debug,
+ maxConnections: this._options.maxConnections,
+ cors: this._options.cors,
+ paramsStore: this._paramsStore,
+ endpointStore: this._endpointStore,
+ chunking: this._options.chunking,
+ resume: this._options.resume,
+ blobs: this._options.blobs,
+ log: qq.bind(self.log, self),
+ preventRetryParam: this._options.retry.preventRetryResponseProperty,
+ onProgress: function(id, name, loaded, total) {
+ if (loaded < 0 || total < 0) {
+ return;
+ }
+ if (lastOnProgress[id]) {
+ if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ } else {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ lastOnProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onComplete: function(id, name, result, xhr) {
+ delete lastOnProgress[id];
+ var status = self.getUploads({
+ id: id
+ }).status, retVal;
+ if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {
+ return;
+ }
+ retVal = self._onComplete(id, name, result, xhr);
+ if (retVal instanceof qq.Promise) {
+ retVal.done(function() {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ });
+ } else {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ }
+ },
+ onCancel: function(id, name, cancelFinalizationEffort) {
+ var promise = new qq.Promise();
+ self._handleCheckedCallback({
+ name: "onCancel",
+ callback: qq.bind(self._options.callbacks.onCancel, self, id, name),
+ onFailure: promise.failure,
+ onSuccess: function() {
+ cancelFinalizationEffort.then(function() {
+ self._onCancel(id, name);
+ });
+ promise.success();
+ },
+ identifier: id
+ });
+ return promise;
+ },
+ onUploadPrep: qq.bind(this._onUploadPrep, this),
+ onUpload: function(id, name) {
+ self._onUpload(id, name);
+ self._options.callbacks.onUpload(id, name);
+ },
+ onUploadChunk: function(id, name, chunkData) {
+ self._onUploadChunk(id, chunkData);
+ self._options.callbacks.onUploadChunk(id, name, chunkData);
+ },
+ onUploadChunkSuccess: function(id, chunkData, result, xhr) {
+ self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);
+ },
+ onResume: function(id, name, chunkData) {
+ return self._options.callbacks.onResume(id, name, chunkData);
+ },
+ onAutoRetry: function(id, name, responseJSON, xhr) {
+ return self._onAutoRetry.apply(self, arguments);
+ },
+ onUuidChanged: function(id, newUuid) {
+ self.log("Server requested UUID change from '" + self.getUuid(id) + "' to '" + newUuid + "'");
+ self.setUuid(id, newUuid);
+ },
+ getName: qq.bind(self.getName, self),
+ getUuid: qq.bind(self.getUuid, self),
+ getSize: qq.bind(self.getSize, self),
+ setSize: qq.bind(self._setSize, self),
+ getDataByUuid: function(uuid) {
+ return self.getUploads({
+ uuid: uuid
+ });
+ },
+ isQueued: function(id) {
+ var status = self.getUploads({
+ id: id
+ }).status;
+ return status === qq.status.QUEUED || status === qq.status.SUBMITTED || status === qq.status.UPLOAD_RETRYING || status === qq.status.PAUSED;
+ },
+ getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,
+ getIdsInBatch: self._uploadData.getIdsInBatch
+ };
+ qq.each(this._options.request, function(prop, val) {
+ options[prop] = val;
+ });
+ options.customHeaders = this._customHeadersStore;
+ if (additionalOptions) {
+ qq.each(additionalOptions, function(key, val) {
+ options[key] = val;
+ });
+ }
+ return new qq.UploadHandlerController(options, namespace);
+ },
+ _fileOrBlobRejected: function(id) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.REJECTED);
+ },
+ _formatSize: function(bytes) {
+ if (bytes === 0) {
+ return bytes + this._options.text.sizeSymbols[0];
+ }
+ var i = -1;
+ do {
+ bytes = bytes / 1e3;
+ i++;
+ } while (bytes > 999);
+ return Math.max(bytes, .1).toFixed(1) + this._options.text.sizeSymbols[i];
+ },
+ _generateExtraButtonSpecs: function() {
+ var self = this;
+ this._extraButtonSpecs = {};
+ qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {
+ var multiple = extraButtonOptionEntry.multiple, validation = qq.extend({}, self._options.validation, true), extraButtonSpec = qq.extend({}, extraButtonOptionEntry);
+ if (multiple === undefined) {
+ multiple = self._options.multiple;
+ }
+ if (extraButtonSpec.validation) {
+ qq.extend(validation, extraButtonOptionEntry.validation, true);
+ }
+ qq.extend(extraButtonSpec, {
+ multiple: multiple,
+ validation: validation
+ }, true);
+ self._initExtraButton(extraButtonSpec);
+ });
+ },
+ _getButton: function(buttonId) {
+ var extraButtonsSpec = this._extraButtonSpecs[buttonId];
+ if (extraButtonsSpec) {
+ return extraButtonsSpec.element;
+ } else if (buttonId === this._defaultButtonId) {
+ return this._options.button;
+ }
+ },
+ _getButtonId: function(buttonOrFileInputOrFile) {
+ var inputs, fileInput, fileBlobOrInput = buttonOrFileInputOrFile;
+ if (fileBlobOrInput instanceof qq.BlobProxy) {
+ fileBlobOrInput = fileBlobOrInput.referenceBlob;
+ }
+ if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {
+ if (qq.isFile(fileBlobOrInput)) {
+ return fileBlobOrInput.qqButtonId;
+ } else if (fileBlobOrInput.tagName.toLowerCase() === "input" && fileBlobOrInput.type.toLowerCase() === "file") {
+ return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ inputs = fileBlobOrInput.getElementsByTagName("input");
+ qq.each(inputs, function(idx, input) {
+ if (input.getAttribute("type") === "file") {
+ fileInput = input;
+ return false;
+ }
+ });
+ if (fileInput) {
+ return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ }
+ },
+ _getNotFinished: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED, qq.status.SUBMITTING, qq.status.SUBMITTED, qq.status.PAUSED ]
+ }).length;
+ },
+ _getValidationBase: function(buttonId) {
+ var extraButtonSpec = this._extraButtonSpecs[buttonId];
+ return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;
+ },
+ _getValidationDescriptor: function(fileWrapper) {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return {
+ name: qq.getFilename(fileWrapper.file.referenceBlob),
+ size: fileWrapper.file.referenceBlob.size
+ };
+ }
+ return {
+ name: this.getUploads({
+ id: fileWrapper.id
+ }).name,
+ size: this.getUploads({
+ id: fileWrapper.id
+ }).size
+ };
+ },
+ _getValidationDescriptors: function(fileWrappers) {
+ var self = this, fileDescriptors = [];
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ fileDescriptors.push(self._getValidationDescriptor(fileWrapper));
+ });
+ return fileDescriptors;
+ },
+ _handleCameraAccess: function() {
+ if (this._options.camera.ios && qq.ios()) {
+ var acceptIosCamera = "image/*;capture=camera", button = this._options.camera.button, buttonId = button ? this._getButtonId(button) : this._defaultButtonId, optionRoot = this._options;
+ if (buttonId && buttonId !== this._defaultButtonId) {
+ optionRoot = this._extraButtonSpecs[buttonId];
+ }
+ optionRoot.multiple = false;
+ if (optionRoot.validation.acceptFiles === null) {
+ optionRoot.validation.acceptFiles = acceptIosCamera;
+ } else {
+ optionRoot.validation.acceptFiles += "," + acceptIosCamera;
+ }
+ qq.each(this._buttons, function(idx, button) {
+ if (button.getButtonId() === buttonId) {
+ button.setMultiple(optionRoot.multiple);
+ button.setAcceptFiles(optionRoot.acceptFiles);
+ return false;
+ }
+ });
+ }
+ },
+ _handleCheckedCallback: function(details) {
+ var self = this, callbackRetVal = details.callback();
+ if (qq.isGenericPromise(callbackRetVal)) {
+ this.log(details.name + " - waiting for " + details.name + " promise to be fulfilled for " + details.identifier);
+ return callbackRetVal.then(function(successParam) {
+ self.log(details.name + " promise success for " + details.identifier);
+ details.onSuccess(successParam);
+ }, function() {
+ if (details.onFailure) {
+ self.log(details.name + " promise failure for " + details.identifier);
+ details.onFailure();
+ } else {
+ self.log(details.name + " promise failure for " + details.identifier);
+ }
+ });
+ }
+ if (callbackRetVal !== false) {
+ details.onSuccess(callbackRetVal);
+ } else {
+ if (details.onFailure) {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Invoking failure callback.");
+ details.onFailure();
+ } else {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Will not proceed.");
+ }
+ }
+ return callbackRetVal;
+ },
+ _handleNewFile: function(file, batchId, newFileWrapperList) {
+ var self = this, uuid = qq.getUniqueId(), size = -1, name = qq.getFilename(file), actualFile = file.blob || file, handler = this._customNewFileHandler ? this._customNewFileHandler : qq.bind(self._handleNewFileGeneric, self);
+ if (!qq.isInput(actualFile) && actualFile.size >= 0) {
+ size = actualFile.size;
+ }
+ handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {
+ uploadData: self._uploadData,
+ paramsStore: self._paramsStore,
+ addFileToHandler: function(id, file) {
+ self._handler.add(id, file);
+ self._netUploadedOrQueued++;
+ self._trackButton(id);
+ }
+ });
+ },
+ _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {
+ var id = this._uploadData.addFile({
+ uuid: uuid,
+ name: name,
+ size: size,
+ batchId: batchId
+ });
+ this._handler.add(id, file);
+ this._trackButton(id);
+ this._netUploadedOrQueued++;
+ fileList.push({
+ id: id,
+ file: file
+ });
+ },
+ _handlePasteSuccess: function(blob, extSuppliedName) {
+ var extension = blob.type.split("/")[1], name = extSuppliedName;
+ if (name == null) {
+ name = this._options.paste.defaultName;
+ }
+ name += "." + extension;
+ this.addFiles({
+ name: name,
+ blob: blob
+ });
+ },
+ _initExtraButton: function(spec) {
+ var button = this._createUploadButton({
+ accept: spec.validation.acceptFiles,
+ allowedExtensions: spec.validation.allowedExtensions,
+ element: spec.element,
+ folders: spec.folders,
+ multiple: spec.multiple,
+ title: spec.fileInputTitle
+ });
+ this._extraButtonSpecs[button.getButtonId()] = spec;
+ },
+ _initFormSupportAndParams: function() {
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore = this._createStore(this._options.request.params, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this._options.request.endpoint = this._formSupport.newEndpoint;
+ }
+ } else {
+ this._paramsStore = this._createStore(this._options.request.params);
+ }
+ },
+ _isDeletePossible: function() {
+ if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {
+ return false;
+ }
+ if (this._options.cors.expected) {
+ if (qq.supportedFeatures.deleteFileCorsXhr) {
+ return true;
+ }
+ if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ },
+ _isAllowedExtension: function(allowed, fileName) {
+ var valid = false;
+ if (!allowed.length) {
+ return true;
+ }
+ qq.each(allowed, function(idx, allowedExt) {
+ if (qq.isString(allowedExt)) {
+ var extRegex = new RegExp("\\." + allowedExt + "$", "i");
+ if (fileName.match(extRegex) != null) {
+ valid = true;
+ return false;
+ }
+ }
+ });
+ return valid;
+ },
+ _itemError: function(code, maybeNameOrNames, item) {
+ var message = this._options.messages[code], allowedExtensions = [], names = [].concat(maybeNameOrNames), name = names[0], buttonId = this._getButtonId(item), validationBase = this._getValidationBase(buttonId), extensionsForMessage, placeholderMatch;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {
+ if (qq.isString(allowedExtension)) {
+ allowedExtensions.push(allowedExtension);
+ }
+ });
+ extensionsForMessage = allowedExtensions.join(", ").toLowerCase();
+ r("{file}", this._options.formatFileName(name));
+ r("{extensions}", extensionsForMessage);
+ r("{sizeLimit}", this._formatSize(validationBase.sizeLimit));
+ r("{minSizeLimit}", this._formatSize(validationBase.minSizeLimit));
+ placeholderMatch = message.match(/(\{\w+\})/g);
+ if (placeholderMatch !== null) {
+ qq.each(placeholderMatch, function(idx, placeholder) {
+ r(placeholder, names[idx]);
+ });
+ }
+ this._options.callbacks.onError(null, name, message, undefined);
+ return message;
+ },
+ _manualRetry: function(id, callback) {
+ if (this._onBeforeManualRetry(id)) {
+ this._netUploadedOrQueued++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ if (callback) {
+ callback(id);
+ } else {
+ this._handler.retry(id);
+ }
+ return true;
+ }
+ },
+ _maybeAllComplete: function(id, status) {
+ var self = this, notFinished = this._getNotFinished();
+ if (status === qq.status.UPLOAD_SUCCESSFUL) {
+ this._succeededSinceLastAllComplete.push(id);
+ } else if (status === qq.status.UPLOAD_FAILED) {
+ this._failedSinceLastAllComplete.push(id);
+ }
+ if (notFinished === 0 && (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {
+ setTimeout(function() {
+ self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);
+ }, 0);
+ }
+ },
+ _maybeHandleIos8SafariWorkaround: function() {
+ var self = this;
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ setTimeout(function() {
+ window.alert(self._options.messages.unsupportedBrowserIos8Safari);
+ }, 0);
+ throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);
+ }
+ },
+ _maybeParseAndSendUploadError: function(id, name, response, xhr) {
+ if (!response.success) {
+ if (xhr && xhr.status !== 200 && !response.error) {
+ this._options.callbacks.onError(id, name, "XHR returned response code " + xhr.status, xhr);
+ } else {
+ var errorReason = response.error ? response.error : this._options.text.defaultResponseError;
+ this._options.callbacks.onError(id, name, errorReason, xhr);
+ }
+ }
+ },
+ _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {
+ var self = this;
+ if (items.length > index) {
+ if (validItem || !this._options.validation.stopOnFirstInvalidFile) {
+ setTimeout(function() {
+ var validationDescriptor = self._getValidationDescriptor(items[index]), buttonId = self._getButtonId(items[index].file), button = self._getButton(buttonId);
+ self._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),
+ onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),
+ onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),
+ identifier: "Item '" + validationDescriptor.name + "', size: " + validationDescriptor.size
+ });
+ }, 0);
+ } else if (!validItem) {
+ for (;index < items.length; index++) {
+ self._fileOrBlobRejected(items[index].id);
+ }
+ }
+ }
+ },
+ _onAllComplete: function(successful, failed) {
+ this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);
+ this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ },
+ _onAutoRetry: function(id, name, responseJSON, xhr, callback) {
+ var self = this;
+ self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];
+ if (self._shouldAutoRetry(id, name, responseJSON)) {
+ var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1e3;
+ self._maybeParseAndSendUploadError.apply(self, arguments);
+ self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);
+ self._onBeforeAutoRetry(id, name);
+ self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ self._retryTimeouts[id] = setTimeout(function() {
+ self.log("Starting retry for " + name + "...");
+ if (callback) {
+ callback(id);
+ } else {
+ self._handler.retry(id);
+ }
+ }, retryWaitPeriod);
+ return true;
+ }
+ },
+ _onBeforeAutoRetry: function(id, name) {
+ this.log("Waiting " + this._options.retry.autoAttemptDelay + " seconds before retrying " + name + "...");
+ },
+ _onBeforeManualRetry: function(id) {
+ var itemLimit = this._currentItemLimit, fileName;
+ if (this._preventRetries[id]) {
+ this.log("Retries are forbidden for id " + id, "warn");
+ return false;
+ } else if (this._handler.isValid(id)) {
+ fileName = this.getName(id);
+ if (this._options.callbacks.onManualRetry(id, fileName) === false) {
+ return false;
+ }
+ if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {
+ this._itemError("retryFailTooManyItems");
+ return false;
+ }
+ this.log("Retrying upload for '" + fileName + "' (id: " + id + ")...");
+ return true;
+ } else {
+ this.log("'" + id + "' is not a valid file ID", "error");
+ return false;
+ }
+ },
+ _onCancel: function(id, name) {
+ this._netUploadedOrQueued--;
+ clearTimeout(this._retryTimeouts[id]);
+ var storedItemIndex = qq.indexOf(this._storedIds, id);
+ if (!this._options.autoUpload && storedItemIndex >= 0) {
+ this._storedIds.splice(storedItemIndex, 1);
+ }
+ this._uploadData.setStatus(id, qq.status.CANCELED);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ if (!result.success) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);
+ if (result[this._options.retry.preventRetryResponseProperty] === true) {
+ this._preventRetries[id] = true;
+ }
+ } else {
+ if (result.thumbnailUrl) {
+ this._thumbnailUrls[id] = result.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);
+ }
+ this._maybeParseAndSendUploadError(id, name, result, xhr);
+ return result.success ? true : false;
+ },
+ _onDelete: function(id) {
+ this._uploadData.setStatus(id, qq.status.DELETING);
+ },
+ _onDeleteComplete: function(id, xhrOrXdr, isError) {
+ var name = this.getName(id);
+ if (isError) {
+ this._uploadData.setStatus(id, qq.status.DELETE_FAILED);
+ this.log("Delete request for '" + name + "' has failed.", "error");
+ if (xhrOrXdr.withCredentials === undefined) {
+ this._options.callbacks.onError(id, name, "Delete request failed", xhrOrXdr);
+ } else {
+ this._options.callbacks.onError(id, name, "Delete request failed with response code " + xhrOrXdr.status, xhrOrXdr);
+ }
+ } else {
+ this._netUploadedOrQueued--;
+ this._netUploaded--;
+ this._handler.expunge(id);
+ this._uploadData.setStatus(id, qq.status.DELETED);
+ this.log("Delete request for '" + name + "' has succeeded.");
+ }
+ },
+ _onInputChange: function(input) {
+ var fileIndex;
+ if (qq.supportedFeatures.ajaxUploading) {
+ for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {
+ this._annotateWithButtonId(input.files[fileIndex], input);
+ }
+ this.addFiles(input.files);
+ } else if (input.value.length > 0) {
+ this.addFiles(input);
+ }
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);
+ },
+ _onSubmit: function(id, name) {},
+ _onSubmitCallbackSuccess: function(id, name) {
+ this._onSubmit.apply(this, arguments);
+ this._uploadData.setStatus(id, qq.status.SUBMITTED);
+ this._onSubmitted.apply(this, arguments);
+ if (this._options.autoUpload) {
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ this._uploadFile(id);
+ } else {
+ this._storeForLater(id);
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ }
+ },
+ _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {
+ var uuid = this.getUuid(id), adjustedOnSuccessCallback;
+ if (onSuccessCallback) {
+ adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);
+ }
+ if (this._isDeletePossible()) {
+ this._handleCheckedCallback({
+ name: "onSubmitDelete",
+ callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),
+ onSuccess: adjustedOnSuccessCallback || qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),
+ identifier: id
+ });
+ return true;
+ } else {
+ this.log("Delete request ignored for ID " + id + ", delete feature is disabled or request not possible " + "due to CORS on a user agent that does not support pre-flighting.", "warn");
+ return false;
+ }
+ },
+ _onSubmitted: function(id) {},
+ _onTotalProgress: function(loaded, total) {
+ this._options.callbacks.onTotalProgress(loaded, total);
+ },
+ _onUploadPrep: function(id) {},
+ _onUpload: function(id, name) {
+ this._uploadData.setStatus(id, qq.status.UPLOADING);
+ },
+ _onUploadChunk: function(id, chunkData) {},
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.PAUSED) {
+ clearTimeout(this._retryTimeouts[id]);
+ }
+ },
+ _onValidateBatchCallbackFailure: function(fileWrappers) {
+ var self = this;
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ self._fileOrBlobRejected(fileWrapper.id);
+ });
+ },
+ _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {
+ var errorMessage, itemLimit = this._currentItemLimit, proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;
+ if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {
+ if (items.length > 0) {
+ this._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),
+ onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),
+ onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),
+ identifier: "Item '" + items[0].file.name + "', size: " + items[0].file.size
+ });
+ } else {
+ this._itemError("noFilesError");
+ }
+ } else {
+ this._onValidateBatchCallbackFailure(items);
+ errorMessage = this._options.messages.tooManyItemsError.replace(/\{netItems\}/g, proposedNetFilesUploadedOrQueued).replace(/\{itemLimit\}/g, itemLimit);
+ this._batchError(errorMessage);
+ }
+ },
+ _onValidateCallbackFailure: function(items, index, params, endpoint) {
+ var nextIndex = index + 1;
+ this._fileOrBlobRejected(items[index].id, items[index].file.name);
+ this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ },
+ _onValidateCallbackSuccess: function(items, index, params, endpoint) {
+ var self = this, nextIndex = index + 1, validationDescriptor = this._getValidationDescriptor(items[index]);
+ this._validateFileOrBlobData(items[index], validationDescriptor).then(function() {
+ self._upload(items[index].id, params, endpoint);
+ self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);
+ }, function() {
+ self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ });
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ if (items.length === 0) {
+ this._itemError("noFilesError");
+ return;
+ }
+ var validationDescriptors = this._getValidationDescriptors(items), buttonId = this._getButtonId(items[0].file), button = this._getButton(buttonId);
+ this._handleCheckedCallback({
+ name: "onValidateBatch",
+ callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),
+ onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),
+ onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),
+ identifier: "batch validation"
+ });
+ },
+ _preventLeaveInProgress: function() {
+ var self = this;
+ this._disposeSupport.attach(window, "beforeunload", function(e) {
+ if (self.getInProgress()) {
+ e = e || window.event;
+ e.returnValue = self._options.messages.onLeave;
+ return self._options.messages.onLeave;
+ }
+ });
+ },
+ _refreshSessionData: function() {
+ var self = this, options = this._options.session;
+ if (qq.Session && this._options.session.endpoint != null) {
+ if (!this._session) {
+ qq.extend(options, {
+ cors: this._options.cors
+ });
+ options.log = qq.bind(this.log, this);
+ options.addFileRecord = qq.bind(this._addCannedFile, this);
+ this._session = new qq.Session(options);
+ }
+ setTimeout(function() {
+ self._session.refresh().then(function(response, xhrOrXdr) {
+ self._sessionRequestComplete();
+ self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);
+ }, function(response, xhrOrXdr) {
+ self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);
+ });
+ }, 0);
+ }
+ },
+ _sessionRequestComplete: function() {},
+ _setSize: function(id, newSize) {
+ this._uploadData.updateSize(id, newSize);
+ this._totalProgress && this._totalProgress.onNewSize(id);
+ },
+ _shouldAutoRetry: function(id, name, responseJSON) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!this._preventRetries[id] && this._options.retry.enableAuto && uploadData.status !== qq.status.PAUSED) {
+ if (this._autoRetries[id] === undefined) {
+ this._autoRetries[id] = 0;
+ }
+ if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {
+ this._autoRetries[id] += 1;
+ return true;
+ }
+ }
+ return false;
+ },
+ _storeForLater: function(id) {
+ this._storedIds.push(id);
+ },
+ _trackButton: function(id) {
+ var buttonId;
+ if (qq.supportedFeatures.ajaxUploading) {
+ buttonId = this._handler.getFile(id).qqButtonId;
+ } else {
+ buttonId = this._getButtonId(this._handler.getInput(id));
+ }
+ if (buttonId) {
+ this._buttonIdsForFileIds[id] = buttonId;
+ }
+ },
+ _updateFormSupportAndParams: function(formElementOrId) {
+ this._options.form.element = formElementOrId;
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this.setEndpoint(this._formSupport.newEndpoint);
+ }
+ }
+ },
+ _upload: function(id, params, endpoint) {
+ var name = this.getName(id);
+ if (params) {
+ this.setParams(params, id);
+ }
+ if (endpoint) {
+ this.setEndpoint(endpoint, id);
+ }
+ this._handleCheckedCallback({
+ name: "onSubmit",
+ callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),
+ onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),
+ onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),
+ identifier: id
+ });
+ },
+ _uploadFile: function(id) {
+ if (!this._handler.upload(id)) {
+ this._uploadData.setStatus(id, qq.status.QUEUED);
+ }
+ },
+ _uploadStoredFiles: function() {
+ var idToUpload, stillSubmitting, self = this;
+ while (this._storedIds.length) {
+ idToUpload = this._storedIds.shift();
+ this._uploadFile(idToUpload);
+ }
+ stillSubmitting = this.getUploads({
+ status: qq.status.SUBMITTING
+ }).length;
+ if (stillSubmitting) {
+ qq.log("Still waiting for " + stillSubmitting + " files to clear submit queue. Will re-parse stored IDs array shortly.");
+ setTimeout(function() {
+ self._uploadStoredFiles();
+ }, 1e3);
+ }
+ },
+ _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {
+ var self = this, file = function() {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return fileWrapper.file.referenceBlob;
+ }
+ return fileWrapper.file;
+ }(), name = validationDescriptor.name, size = validationDescriptor.size, buttonId = this._getButtonId(fileWrapper.file), validationBase = this._getValidationBase(buttonId), validityChecker = new qq.Promise();
+ validityChecker.then(function() {}, function() {
+ self._fileOrBlobRejected(fileWrapper.id, name);
+ });
+ if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {
+ this._itemError("typeError", name, file);
+ return validityChecker.failure();
+ }
+ if (!this._options.validation.allowEmpty && size === 0) {
+ this._itemError("emptyError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {
+ this._itemError("sizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && size < validationBase.minSizeLimit) {
+ this._itemError("minSizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {
+ new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(validityChecker.success, function(errorCode) {
+ self._itemError(errorCode + "ImageError", name, file);
+ validityChecker.failure();
+ });
+ } else {
+ validityChecker.success();
+ }
+ return validityChecker;
+ },
+ _wrapCallbacks: function() {
+ var self, safeCallback, prop;
+ self = this;
+ safeCallback = function(name, callback, args) {
+ var errorMsg;
+ try {
+ return callback.apply(self, args);
+ } catch (exception) {
+ errorMsg = exception.message || exception.toString();
+ self.log("Caught exception in '" + name + "' callback - " + errorMsg, "error");
+ }
+ };
+ for (prop in this._options.callbacks) {
+ (function() {
+ var callbackName, callbackFunc;
+ callbackName = prop;
+ callbackFunc = self._options.callbacks[callbackName];
+ self._options.callbacks[callbackName] = function() {
+ return safeCallback(callbackName, callbackFunc, arguments);
+ };
+ })();
+ }
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.FineUploaderBasic = function(o) {
+ var self = this;
+ this._options = {
+ debug: false,
+ button: null,
+ multiple: true,
+ maxConnections: 3,
+ disableCancelForFormUploads: false,
+ autoUpload: true,
+ request: {
+ customHeaders: {},
+ endpoint: "/server/upload",
+ filenameParam: "qqfilename",
+ forceMultipart: true,
+ inputName: "qqfile",
+ method: "POST",
+ params: {},
+ paramsInBody: true,
+ totalFileSizeName: "qqtotalfilesize",
+ uuidName: "qquuid"
+ },
+ validation: {
+ allowedExtensions: [],
+ sizeLimit: 0,
+ minSizeLimit: 0,
+ itemLimit: 0,
+ stopOnFirstInvalidFile: true,
+ acceptFiles: null,
+ image: {
+ maxHeight: 0,
+ maxWidth: 0,
+ minHeight: 0,
+ minWidth: 0
+ },
+ allowEmpty: false
+ },
+ callbacks: {
+ onSubmit: function(id, name) {},
+ onSubmitted: function(id, name) {},
+ onComplete: function(id, name, responseJSON, maybeXhr) {},
+ onAllComplete: function(successful, failed) {},
+ onCancel: function(id, name) {},
+ onUpload: function(id, name) {},
+ onUploadChunk: function(id, name, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onProgress: function(id, name, loaded, total) {},
+ onTotalProgress: function(loaded, total) {},
+ onError: function(id, name, reason, maybeXhrOrXdr) {},
+ onAutoRetry: function(id, name, attemptNumber) {},
+ onManualRetry: function(id, name) {},
+ onValidateBatch: function(fileOrBlobData) {},
+ onValidate: function(fileOrBlobData) {},
+ onSubmitDelete: function(id) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {},
+ onPasteReceived: function(blob) {},
+ onStatusChange: function(id, oldStatus, newStatus) {},
+ onSessionRequestComplete: function(response, success, xhrOrXdr) {}
+ },
+ messages: {
+ typeError: "{file} has an invalid extension. Valid extension(s): {extensions}.",
+ sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
+ minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
+ emptyError: "{file} is empty, please select files again without it.",
+ noFilesError: "No files to upload.",
+ tooManyItemsError: "Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.",
+ maxHeightImageError: "Image is too tall.",
+ maxWidthImageError: "Image is too wide.",
+ minHeightImageError: "Image is not tall enough.",
+ minWidthImageError: "Image is not wide enough.",
+ retryFailTooManyItems: "Retry failed - you have reached your file limit.",
+ onLeave: "The files are being uploaded, if you leave now the upload will be canceled.",
+ unsupportedBrowserIos8Safari: "Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues."
+ },
+ retry: {
+ enableAuto: false,
+ maxAutoAttempts: 3,
+ autoAttemptDelay: 5,
+ preventRetryResponseProperty: "preventRetry"
+ },
+ classes: {
+ buttonHover: "qq-upload-button-hover",
+ buttonFocus: "qq-upload-button-focus"
+ },
+ chunking: {
+ enabled: false,
+ concurrent: {
+ enabled: false
+ },
+ mandatory: false,
+ paramNames: {
+ partIndex: "qqpartindex",
+ partByteOffset: "qqpartbyteoffset",
+ chunkSize: "qqchunksize",
+ totalFileSize: "qqtotalfilesize",
+ totalParts: "qqtotalparts"
+ },
+ partSize: 2e6,
+ success: {
+ endpoint: null
+ }
+ },
+ resume: {
+ enabled: false,
+ recordsExpireIn: 7,
+ paramNames: {
+ resuming: "qqresume"
+ }
+ },
+ formatFileName: function(fileOrBlobName) {
+ return fileOrBlobName;
+ },
+ text: {
+ defaultResponseError: "Upload failure reason unknown",
+ fileInputTitle: "file input",
+ sizeSymbols: [ "kB", "MB", "GB", "TB", "PB", "EB" ]
+ },
+ deleteFile: {
+ enabled: false,
+ method: "DELETE",
+ endpoint: "/server/upload",
+ customHeaders: {},
+ params: {}
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false,
+ allowXdr: false
+ },
+ blobs: {
+ defaultName: "misc_data"
+ },
+ paste: {
+ targetElement: null,
+ defaultName: "pasted_image"
+ },
+ camera: {
+ ios: false,
+ button: null
+ },
+ extraButtons: [],
+ session: {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ refreshOnReset: true
+ },
+ form: {
+ element: "qq-form",
+ autoUpload: false,
+ interceptSubmit: true
+ },
+ scaling: {
+ customResizer: null,
+ sendOriginal: true,
+ orient: true,
+ defaultType: null,
+ defaultQuality: 80,
+ failureText: "Failed to scale",
+ includeExif: false,
+ sizes: []
+ },
+ workarounds: {
+ iosEmptyVideos: true,
+ ios8SafariUploads: true,
+ ios8BrowserCrash: false
+ }
+ };
+ qq.extend(this._options, o, true);
+ this._buttons = [];
+ this._extraButtonSpecs = {};
+ this._buttonIdsForFileIds = [];
+ this._wrapCallbacks();
+ this._disposeSupport = new qq.DisposeSupport();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData = this._createUploadDataTracker();
+ this._initFormSupportAndParams();
+ this._customHeadersStore = this._createStore(this._options.request.customHeaders);
+ this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);
+ this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);
+ this._endpointStore = this._createStore(this._options.request.endpoint);
+ this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);
+ this._handler = this._createUploadHandler();
+ this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();
+ if (this._options.button) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._options.button,
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._generateExtraButtonSpecs();
+ this._handleCameraAccess();
+ if (this._options.paste.targetElement) {
+ if (qq.PasteSupport) {
+ this._pasteHandler = this._createPasteHandler();
+ } else {
+ this.log("Paste support module not found", "error");
+ }
+ }
+ this._preventLeaveInProgress();
+ this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));
+ this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._scaler = qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this)) || {};
+ if (this._scaler.enabled) {
+ this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);
+ }
+ if (qq.TotalProgress && qq.supportedFeatures.progressBar) {
+ this._totalProgress = new qq.TotalProgress(qq.bind(this._onTotalProgress, this), function(id) {
+ var entry = self._uploadData.retrieve({
+ id: id
+ });
+ return entry && entry.size || 0;
+ });
+ }
+ this._currentItemLimit = this._options.validation.itemLimit;
+ };
+ qq.FineUploaderBasic.prototype = qq.basePublicApi;
+ qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);
+ })();
+ qq.AjaxRequester = function(o) {
+ "use strict";
+ var log, shouldParamsBeInQueryString, queue = [], requestData = {}, options = {
+ acceptHeader: null,
+ validMethods: [ "PATCH", "POST", "PUT" ],
+ method: "POST",
+ contentType: "application/x-www-form-urlencoded",
+ maxConnections: 3,
+ customHeaders: {},
+ endpointStore: {},
+ paramsStore: {},
+ mandatedParams: {},
+ allowXRequestedWithAndCacheControl: true,
+ successfulResponseCodes: {
+ DELETE: [ 200, 202, 204 ],
+ PATCH: [ 200, 201, 202, 203, 204 ],
+ POST: [ 200, 201, 202, 203, 204 ],
+ PUT: [ 200, 201, 202, 203, 204 ],
+ GET: [ 200 ]
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onSend: function(id) {},
+ onComplete: function(id, xhrOrXdr, isError) {},
+ onProgress: null
+ };
+ qq.extend(options, o);
+ log = options.log;
+ if (qq.indexOf(options.validMethods, options.method) < 0) {
+ throw new Error("'" + options.method + "' is not a supported method for this type of request!");
+ }
+ function isSimpleMethod() {
+ return qq.indexOf([ "GET", "POST", "HEAD" ], options.method) >= 0;
+ }
+ function containsNonSimpleHeaders(headers) {
+ var containsNonSimple = false;
+ qq.each(containsNonSimple, function(idx, header) {
+ if (qq.indexOf([ "Accept", "Accept-Language", "Content-Language", "Content-Type" ], header) < 0) {
+ containsNonSimple = true;
+ return false;
+ }
+ });
+ return containsNonSimple;
+ }
+ function isXdr(xhr) {
+ return options.cors.expected && xhr.withCredentials === undefined;
+ }
+ function getCorsAjaxTransport() {
+ var xhrOrXdr;
+ if (window.XMLHttpRequest || window.ActiveXObject) {
+ xhrOrXdr = qq.createXhrInstance();
+ if (xhrOrXdr.withCredentials === undefined) {
+ xhrOrXdr = new XDomainRequest();
+ xhrOrXdr.onload = function() {};
+ xhrOrXdr.onerror = function() {};
+ xhrOrXdr.ontimeout = function() {};
+ xhrOrXdr.onprogress = function() {};
+ }
+ }
+ return xhrOrXdr;
+ }
+ function getXhrOrXdr(id, suppliedXhr) {
+ var xhrOrXdr = requestData[id].xhr;
+ if (!xhrOrXdr) {
+ if (suppliedXhr) {
+ xhrOrXdr = suppliedXhr;
+ } else {
+ if (options.cors.expected) {
+ xhrOrXdr = getCorsAjaxTransport();
+ } else {
+ xhrOrXdr = qq.createXhrInstance();
+ }
+ }
+ requestData[id].xhr = xhrOrXdr;
+ }
+ return xhrOrXdr;
+ }
+ function dequeue(id) {
+ var i = qq.indexOf(queue, id), max = options.maxConnections, nextId;
+ delete requestData[id];
+ queue.splice(i, 1);
+ if (queue.length >= max && i < max) {
+ nextId = queue[max - 1];
+ sendRequest(nextId);
+ }
+ }
+ function onComplete(id, xdrError) {
+ var xhr = getXhrOrXdr(id), method = options.method, isError = xdrError === true;
+ dequeue(id);
+ if (isError) {
+ log(method + " request for " + id + " has failed", "error");
+ } else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {
+ isError = true;
+ log(method + " request for " + id + " has failed - response code " + xhr.status, "error");
+ }
+ options.onComplete(id, xhr, isError);
+ }
+ function getParams(id) {
+ var onDemandParams = requestData[id].additionalParams, mandatedParams = options.mandatedParams, params;
+ if (options.paramsStore.get) {
+ params = options.paramsStore.get(id);
+ }
+ if (onDemandParams) {
+ qq.each(onDemandParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ if (mandatedParams) {
+ qq.each(mandatedParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ return params;
+ }
+ function sendRequest(id, optXhr) {
+ var xhr = getXhrOrXdr(id, optXhr), method = options.method, params = getParams(id), payload = requestData[id].payload, url;
+ options.onSend(id);
+ url = createUrl(id, params, requestData[id].additionalQueryParams);
+ if (isXdr(xhr)) {
+ xhr.onload = getXdrLoadHandler(id);
+ xhr.onerror = getXdrErrorHandler(id);
+ } else {
+ xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);
+ }
+ registerForUploadProgress(id);
+ xhr.open(method, url, true);
+ if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {
+ xhr.withCredentials = true;
+ }
+ setHeaders(id);
+ log("Sending " + method + " request for " + id);
+ if (payload) {
+ xhr.send(payload);
+ } else if (shouldParamsBeInQueryString || !params) {
+ xhr.send();
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/x-www-form-urlencoded") >= 0) {
+ xhr.send(qq.obj2url(params, ""));
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/json") >= 0) {
+ xhr.send(JSON.stringify(params));
+ } else {
+ xhr.send(params);
+ }
+ return xhr;
+ }
+ function createUrl(id, params, additionalQueryParams) {
+ var endpoint = options.endpointStore.get(id), addToPath = requestData[id].addToPath;
+ if (addToPath != undefined) {
+ endpoint += "/" + addToPath;
+ }
+ if (shouldParamsBeInQueryString && params) {
+ endpoint = qq.obj2url(params, endpoint);
+ }
+ if (additionalQueryParams) {
+ endpoint = qq.obj2url(additionalQueryParams, endpoint);
+ }
+ return endpoint;
+ }
+ function getXhrReadyStateChangeHandler(id) {
+ return function() {
+ if (getXhrOrXdr(id).readyState === 4) {
+ onComplete(id);
+ }
+ };
+ }
+ function registerForUploadProgress(id) {
+ var onProgress = options.onProgress;
+ if (onProgress) {
+ getXhrOrXdr(id).upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ onProgress(id, e.loaded, e.total);
+ }
+ };
+ }
+ }
+ function getXdrLoadHandler(id) {
+ return function() {
+ onComplete(id);
+ };
+ }
+ function getXdrErrorHandler(id) {
+ return function() {
+ onComplete(id, true);
+ };
+ }
+ function setHeaders(id) {
+ var xhr = getXhrOrXdr(id), customHeaders = options.customHeaders, onDemandHeaders = requestData[id].additionalHeaders || {}, method = options.method, allHeaders = {};
+ if (!isXdr(xhr)) {
+ options.acceptHeader && xhr.setRequestHeader("Accept", options.acceptHeader);
+ if (options.allowXRequestedWithAndCacheControl) {
+ if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ xhr.setRequestHeader("Cache-Control", "no-cache");
+ }
+ }
+ if (options.contentType && (method === "POST" || method === "PUT")) {
+ xhr.setRequestHeader("Content-Type", options.contentType);
+ }
+ qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);
+ qq.extend(allHeaders, onDemandHeaders);
+ qq.each(allHeaders, function(name, val) {
+ xhr.setRequestHeader(name, val);
+ });
+ }
+ }
+ function isResponseSuccessful(responseCode) {
+ return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;
+ }
+ function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {
+ requestData[id] = {
+ addToPath: addToPath,
+ additionalParams: additionalParams,
+ additionalQueryParams: additionalQueryParams,
+ additionalHeaders: additionalHeaders,
+ payload: payload
+ };
+ var len = queue.push(id);
+ if (len <= options.maxConnections) {
+ return sendRequest(id, optXhr);
+ }
+ }
+ shouldParamsBeInQueryString = options.method === "GET" || options.method === "DELETE";
+ qq.extend(this, {
+ initTransport: function(id) {
+ var path, params, headers, payload, cacheBuster, additionalQueryParams;
+ return {
+ withPath: function(appendToPath) {
+ path = appendToPath;
+ return this;
+ },
+ withParams: function(additionalParams) {
+ params = additionalParams;
+ return this;
+ },
+ withQueryParams: function(_additionalQueryParams_) {
+ additionalQueryParams = _additionalQueryParams_;
+ return this;
+ },
+ withHeaders: function(additionalHeaders) {
+ headers = additionalHeaders;
+ return this;
+ },
+ withPayload: function(thePayload) {
+ payload = thePayload;
+ return this;
+ },
+ withCacheBuster: function() {
+ cacheBuster = true;
+ return this;
+ },
+ send: function(optXhr) {
+ if (cacheBuster && qq.indexOf([ "GET", "DELETE" ], options.method) >= 0) {
+ params.qqtimestamp = new Date().getTime();
+ }
+ return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);
+ }
+ };
+ },
+ canceled: function(id) {
+ dequeue(id);
+ }
+ });
+ };
+ qq.UploadHandler = function(spec) {
+ "use strict";
+ var proxy = spec.proxy, fileState = {}, onCancel = proxy.onCancel, getName = proxy.getName;
+ qq.extend(this, {
+ add: function(id, fileItem) {
+ fileState[id] = fileItem;
+ fileState[id].temp = {};
+ },
+ cancel: function(id) {
+ var self = this, cancelFinalizationEffort = new qq.Promise(), onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);
+ onCancelRetVal.then(function() {
+ if (self.isValid(id)) {
+ fileState[id].canceled = true;
+ self.expunge(id);
+ }
+ cancelFinalizationEffort.success();
+ });
+ },
+ expunge: function(id) {
+ delete fileState[id];
+ },
+ getThirdPartyFileId: function(id) {
+ return fileState[id].key;
+ },
+ isValid: function(id) {
+ return fileState[id] !== undefined;
+ },
+ reset: function() {
+ fileState = {};
+ },
+ _getFileState: function(id) {
+ return fileState[id];
+ },
+ _setThirdPartyFileId: function(id, thirdPartyFileId) {
+ fileState[id].key = thirdPartyFileId;
+ },
+ _wasCanceled: function(id) {
+ return !!fileState[id].canceled;
+ }
+ });
+ };
+ qq.UploadHandlerController = function(o, namespace) {
+ "use strict";
+ var controller = this, chunkingPossible = false, concurrentChunkingPossible = false, chunking, preventRetryResponse, log, handler, options = {
+ paramsStore: {},
+ maxConnections: 3,
+ chunking: {
+ enabled: false,
+ multiple: {
+ enabled: false
+ }
+ },
+ log: function(str, level) {},
+ onProgress: function(id, fileName, loaded, total) {},
+ onComplete: function(id, fileName, response, xhr) {},
+ onCancel: function(id, fileName) {},
+ onUploadPrep: function(id) {},
+ onUpload: function(id, fileName) {},
+ onUploadChunk: function(id, fileName, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, response, xhr) {},
+ onAutoRetry: function(id, fileName, response, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onUuidChanged: function(id, newUuid) {},
+ getName: function(id) {},
+ setSize: function(id, newSize) {},
+ isQueued: function(id) {},
+ getIdsInProxyGroup: function(id) {},
+ getIdsInBatch: function(id) {}
+ }, chunked = {
+ done: function(id, chunkIdx, response, xhr) {
+ var chunkData = handler._getChunkData(id, chunkIdx);
+ handler._getFileState(id).attemptingResume = false;
+ delete handler._getFileState(id).temp.chunkProgress[chunkIdx];
+ handler._getFileState(id).loaded += chunkData.size;
+ options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);
+ },
+ finalize: function(id) {
+ var size = options.getSize(id), name = options.getName(id);
+ log("All chunks have been uploaded for " + id + " - finalizing....");
+ handler.finalizeChunks(id).then(function(response, xhr) {
+ log("Finalize successful for " + id);
+ var normaizedResponse = upload.normalizeResponse(response, true);
+ options.onProgress(id, name, size, size);
+ handler._maybeDeletePersistedChunkData(id);
+ upload.cleanup(id, normaizedResponse, xhr);
+ }, function(response, xhr) {
+ var normaizedResponse = upload.normalizeResponse(response, false);
+ log("Problem finalizing chunks for file ID " + id + " - " + normaizedResponse.error, "error");
+ if (normaizedResponse.reset) {
+ chunked.reset(id);
+ }
+ if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {
+ upload.cleanup(id, normaizedResponse, xhr);
+ }
+ });
+ },
+ handleFailure: function(chunkIdx, id, response, xhr) {
+ var name = options.getName(id);
+ log("Chunked upload request failed for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var responseToReport = upload.normalizeResponse(response, false), inProgressIdx;
+ if (responseToReport.reset) {
+ chunked.reset(id);
+ } else {
+ inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);
+ if (inProgressIdx >= 0) {
+ handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);
+ handler._getFileState(id).chunking.remaining.unshift(chunkIdx);
+ }
+ }
+ if (!handler._getFileState(id).temp.ignoreFailure) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = true;
+ log(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));
+ qq.each(handler._getXhrs(id), function(ckid, ckXhr) {
+ log(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ", id, ckid, ckXhr.readyState));
+ ckXhr.abort();
+ ckXhr._cancelled = true;
+ });
+ handler.moveInProgressToRemaining(id);
+ connectionManager.free(id, true);
+ }
+ if (!options.onAutoRetry(id, name, responseToReport, xhr)) {
+ upload.cleanup(id, responseToReport, xhr);
+ }
+ }
+ },
+ hasMoreParts: function(id) {
+ return !!handler._getFileState(id).chunking.remaining.length;
+ },
+ nextPart: function(id) {
+ var nextIdx = handler._getFileState(id).chunking.remaining.shift();
+ if (nextIdx >= handler._getTotalChunks(id)) {
+ nextIdx = null;
+ }
+ return nextIdx;
+ },
+ reset: function(id) {
+ log("Server or callback has ordered chunking effort to be restarted on next attempt for item ID " + id, "error");
+ handler._maybeDeletePersistedChunkData(id);
+ handler.reevaluateChunking(id);
+ handler._getFileState(id).loaded = 0;
+ },
+ sendNext: function(id) {
+ var size = options.getSize(id), name = options.getName(id), chunkIdx = chunked.nextPart(id), chunkData = handler._getChunkData(id, chunkIdx), resuming = handler._getFileState(id).attemptingResume, inProgressChunks = handler._getFileState(id).chunking.inProgress || [];
+ if (handler._getFileState(id).loaded == null) {
+ handler._getFileState(id).loaded = 0;
+ }
+ if (resuming && options.onResume(id, name, chunkData) === false) {
+ chunked.reset(id);
+ chunkIdx = chunked.nextPart(id);
+ chunkData = handler._getChunkData(id, chunkIdx);
+ resuming = false;
+ }
+ if (chunkIdx == null && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else {
+ log(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.", id, chunkIdx, chunkData.start + 1, chunkData.end, size));
+ options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));
+ inProgressChunks.push(chunkIdx);
+ handler._getFileState(id).chunking.inProgress = inProgressChunks;
+ if (concurrentChunkingPossible) {
+ connectionManager.open(id, chunkIdx);
+ }
+ if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {
+ chunked.sendNext(id);
+ }
+ if (chunkData.blob.size === 0) {
+ log(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.", chunkIdx, id), "error");
+ chunked.handleFailure(chunkIdx, id, "File is no longer available", null);
+ } else {
+ handler.uploadChunk(id, chunkIdx, resuming).then(function success(response, xhr) {
+ log("Chunked upload request succeeded for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var inProgressChunks = handler._getFileState(id).chunking.inProgress || [], responseToReport = upload.normalizeResponse(response, true), inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);
+ log(qq.format("Chunk {} for file {} uploaded successfully.", chunkIdx, id));
+ chunked.done(id, chunkIdx, responseToReport, xhr);
+ if (inProgressChunkIdx >= 0) {
+ inProgressChunks.splice(inProgressChunkIdx, 1);
+ }
+ handler._maybePersistChunkedState(id);
+ if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else if (chunked.hasMoreParts(id)) {
+ chunked.sendNext(id);
+ } else {
+ log(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}", id, JSON.stringify(inProgressChunks)));
+ }
+ }, function failure(response, xhr) {
+ chunked.handleFailure(chunkIdx, id, response, xhr);
+ }).done(function() {
+ handler.clearXhr(id, chunkIdx);
+ });
+ }
+ }
+ }
+ }, connectionManager = {
+ _open: [],
+ _openChunks: {},
+ _waiting: [],
+ available: function() {
+ var max = options.maxConnections, openChunkEntriesCount = 0, openChunksCount = 0;
+ qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {
+ openChunkEntriesCount++;
+ openChunksCount += openChunkIndexes.length;
+ });
+ return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);
+ },
+ free: function(id, dontAllowNext) {
+ var allowNext = !dontAllowNext, waitingIndex = qq.indexOf(connectionManager._waiting, id), connectionsIndex = qq.indexOf(connectionManager._open, id), nextId;
+ delete connectionManager._openChunks[id];
+ if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {
+ log("Generated blob upload has ended for " + id + ", disposing generated blob.");
+ delete handler._getFileState(id).file;
+ }
+ if (waitingIndex >= 0) {
+ connectionManager._waiting.splice(waitingIndex, 1);
+ } else if (allowNext && connectionsIndex >= 0) {
+ connectionManager._open.splice(connectionsIndex, 1);
+ nextId = connectionManager._waiting.shift();
+ if (nextId >= 0) {
+ connectionManager._open.push(nextId);
+ upload.start(nextId);
+ }
+ }
+ },
+ getWaitingOrConnected: function() {
+ var waitingOrConnected = [];
+ qq.each(connectionManager._openChunks, function(fileId, chunks) {
+ if (chunks && chunks.length) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ qq.each(connectionManager._open, function(idx, fileId) {
+ if (!connectionManager._openChunks[fileId]) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);
+ return waitingOrConnected;
+ },
+ isUsingConnection: function(id) {
+ return qq.indexOf(connectionManager._open, id) >= 0;
+ },
+ open: function(id, chunkIdx) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.push(id);
+ }
+ if (connectionManager.available()) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.pop();
+ connectionManager._open.push(id);
+ } else {
+ (function() {
+ var openChunksEntry = connectionManager._openChunks[id] || [];
+ openChunksEntry.push(chunkIdx);
+ connectionManager._openChunks[id] = openChunksEntry;
+ })();
+ }
+ return true;
+ }
+ return false;
+ },
+ reset: function() {
+ connectionManager._waiting = [];
+ connectionManager._open = [];
+ }
+ }, simple = {
+ send: function(id, name) {
+ handler._getFileState(id).loaded = 0;
+ log("Sending simple upload request for " + id);
+ handler.uploadFile(id).then(function(response, optXhr) {
+ log("Simple upload request succeeded for " + id);
+ var responseToReport = upload.normalizeResponse(response, true), size = options.getSize(id);
+ options.onProgress(id, name, size, size);
+ upload.maybeNewUuid(id, responseToReport);
+ upload.cleanup(id, responseToReport, optXhr);
+ }, function(response, optXhr) {
+ log("Simple upload request failed for " + id);
+ var responseToReport = upload.normalizeResponse(response, false);
+ if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {
+ upload.cleanup(id, responseToReport, optXhr);
+ }
+ });
+ }
+ }, upload = {
+ cancel: function(id) {
+ log("Cancelling " + id);
+ options.paramsStore.remove(id);
+ connectionManager.free(id);
+ },
+ cleanup: function(id, response, optXhr) {
+ var name = options.getName(id);
+ options.onComplete(id, name, response, optXhr);
+ if (handler._getFileState(id)) {
+ handler._clearXhrs && handler._clearXhrs(id);
+ }
+ connectionManager.free(id);
+ },
+ getProxyOrBlob: function(id) {
+ return handler.getProxy && handler.getProxy(id) || handler.getFile && handler.getFile(id);
+ },
+ initHandler: function() {
+ var handlerType = namespace ? qq[namespace] : qq.traditional, handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? "Xhr" : "Form";
+ handler = new handlerType[handlerModuleSubtype + "UploadHandler"](options, {
+ getDataByUuid: options.getDataByUuid,
+ getName: options.getName,
+ getSize: options.getSize,
+ getUuid: options.getUuid,
+ log: log,
+ onCancel: options.onCancel,
+ onProgress: options.onProgress,
+ onUuidChanged: options.onUuidChanged
+ });
+ if (handler._removeExpiredChunkingRecords) {
+ handler._removeExpiredChunkingRecords();
+ }
+ },
+ isDeferredEligibleForUpload: function(id) {
+ return options.isQueued(id);
+ },
+ maybeDefer: function(id, blob) {
+ if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {
+ options.onUploadPrep(id);
+ log("Attempting to generate a blob on-demand for " + id);
+ blob.create().then(function(generatedBlob) {
+ log("Generated an on-demand blob for " + id);
+ handler.updateBlob(id, generatedBlob);
+ options.setSize(id, generatedBlob.size);
+ handler.reevaluateChunking(id);
+ upload.maybeSendDeferredFiles(id);
+ }, function(errorMessage) {
+ var errorResponse = {};
+ if (errorMessage) {
+ errorResponse.error = errorMessage;
+ }
+ log(qq.format("Failed to generate blob for ID {}. Error message: {}.", id, errorMessage), "error");
+ options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);
+ upload.maybeSendDeferredFiles(id);
+ connectionManager.free(id);
+ });
+ } else {
+ return upload.maybeSendDeferredFiles(id);
+ }
+ return false;
+ },
+ maybeSendDeferredFiles: function(id) {
+ var idsInGroup = options.getIdsInProxyGroup(id), uploadedThisId = false;
+ if (idsInGroup && idsInGroup.length) {
+ log("Maybe ready to upload proxy group file " + id);
+ qq.each(idsInGroup, function(idx, idInGroup) {
+ if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {
+ uploadedThisId = idInGroup === id;
+ upload.now(idInGroup);
+ } else if (upload.isDeferredEligibleForUpload(idInGroup)) {
+ return false;
+ }
+ });
+ } else {
+ uploadedThisId = true;
+ upload.now(id);
+ }
+ return uploadedThisId;
+ },
+ maybeNewUuid: function(id, response) {
+ if (response.newUuid !== undefined) {
+ options.onUuidChanged(id, response.newUuid);
+ }
+ },
+ normalizeResponse: function(originalResponse, successful) {
+ var response = originalResponse;
+ if (!qq.isObject(originalResponse)) {
+ response = {};
+ if (qq.isString(originalResponse) && !successful) {
+ response.error = originalResponse;
+ }
+ }
+ response.success = successful;
+ return response;
+ },
+ now: function(id) {
+ var name = options.getName(id);
+ if (!controller.isValid(id)) {
+ throw new qq.Error(id + " is not a valid file ID to upload!");
+ }
+ options.onUpload(id, name);
+ if (chunkingPossible && handler._shouldChunkThisFile(id)) {
+ chunked.sendNext(id);
+ } else {
+ simple.send(id, name);
+ }
+ },
+ start: function(id) {
+ var blobToUpload = upload.getProxyOrBlob(id);
+ if (blobToUpload) {
+ return upload.maybeDefer(id, blobToUpload);
+ } else {
+ upload.now(id);
+ return true;
+ }
+ }
+ };
+ qq.extend(this, {
+ add: function(id, file) {
+ handler.add.apply(this, arguments);
+ },
+ upload: function(id) {
+ if (connectionManager.open(id)) {
+ return upload.start(id);
+ }
+ return false;
+ },
+ retry: function(id) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = false;
+ }
+ if (connectionManager.isUsingConnection(id)) {
+ return upload.start(id);
+ } else {
+ return controller.upload(id);
+ }
+ },
+ cancel: function(id) {
+ var cancelRetVal = handler.cancel(id);
+ if (qq.isGenericPromise(cancelRetVal)) {
+ cancelRetVal.then(function() {
+ upload.cancel(id);
+ });
+ } else if (cancelRetVal !== false) {
+ upload.cancel(id);
+ }
+ },
+ cancelAll: function() {
+ var waitingOrConnected = connectionManager.getWaitingOrConnected(), i;
+ if (waitingOrConnected.length) {
+ for (i = waitingOrConnected.length - 1; i >= 0; i--) {
+ controller.cancel(waitingOrConnected[i]);
+ }
+ }
+ connectionManager.reset();
+ },
+ getFile: function(id) {
+ if (handler.getProxy && handler.getProxy(id)) {
+ return handler.getProxy(id).referenceBlob;
+ }
+ return handler.getFile && handler.getFile(id);
+ },
+ isProxied: function(id) {
+ return !!(handler.getProxy && handler.getProxy(id));
+ },
+ getInput: function(id) {
+ if (handler.getInput) {
+ return handler.getInput(id);
+ }
+ },
+ reset: function() {
+ log("Resetting upload handler");
+ controller.cancelAll();
+ connectionManager.reset();
+ handler.reset();
+ },
+ expunge: function(id) {
+ if (controller.isValid(id)) {
+ return handler.expunge(id);
+ }
+ },
+ isValid: function(id) {
+ return handler.isValid(id);
+ },
+ getResumableFilesData: function() {
+ if (handler.getResumableFilesData) {
+ return handler.getResumableFilesData();
+ }
+ return [];
+ },
+ getThirdPartyFileId: function(id) {
+ if (controller.isValid(id)) {
+ return handler.getThirdPartyFileId(id);
+ }
+ },
+ pause: function(id) {
+ if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {
+ connectionManager.free(id);
+ handler.moveInProgressToRemaining(id);
+ return true;
+ }
+ return false;
+ },
+ isResumable: function(id) {
+ return !!handler.isResumable && handler.isResumable(id);
+ }
+ });
+ qq.extend(options, o);
+ log = options.log;
+ chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;
+ concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;
+ preventRetryResponse = function() {
+ var response = {};
+ response[options.preventRetryParam] = true;
+ return response;
+ }();
+ upload.initHandler();
+ };
+ qq.WindowReceiveMessage = function(o) {
+ "use strict";
+ var options = {
+ log: function(message, level) {}
+ }, callbackWrapperDetachers = {};
+ qq.extend(options, o);
+ qq.extend(this, {
+ receiveMessage: function(id, callback) {
+ var onMessageCallbackWrapper = function(event) {
+ callback(event.data);
+ };
+ if (window.postMessage) {
+ callbackWrapperDetachers[id] = qq(window).attach("message", onMessageCallbackWrapper);
+ } else {
+ log("iframe message passing not supported in this browser!", "error");
+ }
+ },
+ stopReceivingMessages: function(id) {
+ if (window.postMessage) {
+ var detacher = callbackWrapperDetachers[id];
+ if (detacher) {
+ detacher();
+ }
+ }
+ }
+ });
+ };
+ qq.FormUploadHandler = function(spec) {
+ "use strict";
+ var options = spec.options, handler = this, proxy = spec.proxy, formHandlerInstanceId = qq.getUniqueId(), onloadCallbacks = {}, detachLoadEvents = {}, postMessageCallbackTimers = {}, isCors = options.isCors, inputName = options.inputName, getUuid = proxy.getUuid, log = proxy.log, corsMessageReceiver = new qq.WindowReceiveMessage({
+ log: log
+ });
+ function expungeFile(id) {
+ delete detachLoadEvents[id];
+ if (isCors) {
+ clearTimeout(postMessageCallbackTimers[id]);
+ delete postMessageCallbackTimers[id];
+ corsMessageReceiver.stopReceivingMessages(id);
+ }
+ var iframe = document.getElementById(handler._getIframeName(id));
+ if (iframe) {
+ iframe.setAttribute("src", "javascript:false;");
+ qq(iframe).remove();
+ }
+ }
+ function getFileIdForIframeName(iframeName) {
+ return iframeName.split("_")[0];
+ }
+ function initIframeForUpload(name) {
+ var iframe = qq.toElement("");
+ iframe.setAttribute("id", name);
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+ return iframe;
+ }
+ function registerPostMessageCallback(iframe, callback) {
+ var iframeName = iframe.id, fileId = getFileIdForIframeName(iframeName), uuid = getUuid(fileId);
+ onloadCallbacks[uuid] = callback;
+ detachLoadEvents[fileId] = qq(iframe).attach("load", function() {
+ if (handler.getInput(fileId)) {
+ log("Received iframe load event for CORS upload request (iframe name " + iframeName + ")");
+ postMessageCallbackTimers[iframeName] = setTimeout(function() {
+ var errorMessage = "No valid message received from loaded iframe for iframe name " + iframeName;
+ log(errorMessage, "error");
+ callback({
+ error: errorMessage
+ });
+ }, 1e3);
+ }
+ });
+ corsMessageReceiver.receiveMessage(iframeName, function(message) {
+ log("Received the following window message: '" + message + "'");
+ var fileId = getFileIdForIframeName(iframeName), response = handler._parseJsonResponse(message), uuid = response.uuid, onloadCallback;
+ if (uuid && onloadCallbacks[uuid]) {
+ log("Handling response for iframe name " + iframeName);
+ clearTimeout(postMessageCallbackTimers[iframeName]);
+ delete postMessageCallbackTimers[iframeName];
+ handler._detachLoadEvent(iframeName);
+ onloadCallback = onloadCallbacks[uuid];
+ delete onloadCallbacks[uuid];
+ corsMessageReceiver.stopReceivingMessages(iframeName);
+ onloadCallback(response);
+ } else if (!uuid) {
+ log("'" + message + "' does not contain a UUID - ignoring.");
+ }
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, fileInput) {
+ super_.add(id, {
+ input: fileInput
+ });
+ fileInput.setAttribute("name", inputName);
+ if (fileInput.parentNode) {
+ qq(fileInput).remove();
+ }
+ },
+ expunge: function(id) {
+ expungeFile(id);
+ super_.expunge(id);
+ },
+ isValid: function(id) {
+ return super_.isValid(id) && handler._getFileState(id).input !== undefined;
+ }
+ };
+ });
+ qq.extend(this, {
+ getInput: function(id) {
+ return handler._getFileState(id).input;
+ },
+ _attachLoadEvent: function(iframe, callback) {
+ var responseDescriptor;
+ if (isCors) {
+ registerPostMessageCallback(iframe, callback);
+ } else {
+ detachLoadEvents[iframe.id] = qq(iframe).attach("load", function() {
+ log("Received response for " + iframe.id);
+ if (!iframe.parentNode) {
+ return;
+ }
+ try {
+ if (iframe.contentDocument && iframe.contentDocument.body && iframe.contentDocument.body.innerHTML == "false") {
+ return;
+ }
+ } catch (error) {
+ log("Error when attempting to access iframe during handling of upload response (" + error.message + ")", "error");
+ responseDescriptor = {
+ success: false
+ };
+ }
+ callback(responseDescriptor);
+ });
+ }
+ },
+ _createIframe: function(id) {
+ var iframeName = handler._getIframeName(id);
+ return initIframeForUpload(iframeName);
+ },
+ _detachLoadEvent: function(id) {
+ if (detachLoadEvents[id] !== undefined) {
+ detachLoadEvents[id]();
+ delete detachLoadEvents[id];
+ }
+ },
+ _getIframeName: function(fileId) {
+ return fileId + "_" + formHandlerInstanceId;
+ },
+ _initFormForUpload: function(spec) {
+ var method = spec.method, endpoint = spec.endpoint, params = spec.params, paramsInBody = spec.paramsInBody, targetName = spec.targetName, form = qq.toElement(""), url = endpoint;
+ if (paramsInBody) {
+ qq.obj2Inputs(params, form);
+ } else {
+ url = qq.obj2url(params, endpoint);
+ }
+ form.setAttribute("action", url);
+ form.setAttribute("target", targetName);
+ form.style.display = "none";
+ document.body.appendChild(form);
+ return form;
+ },
+ _parseJsonResponse: function(innerHtmlOrMessage) {
+ var response = {};
+ try {
+ response = qq.parseJson(innerHtmlOrMessage);
+ } catch (error) {
+ log("Error when attempting to parse iframe upload response (" + error.message + ")", "error");
+ }
+ return response;
+ }
+ });
+ };
+ qq.XhrUploadHandler = function(spec) {
+ "use strict";
+ var handler = this, namespace = spec.options.namespace, proxy = spec.proxy, chunking = spec.options.chunking, resume = spec.options.resume, chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking, resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume, getName = proxy.getName, getSize = proxy.getSize, getUuid = proxy.getUuid, getEndpoint = proxy.getEndpoint, getDataByUuid = proxy.getDataByUuid, onUuidChanged = proxy.onUuidChanged, onProgress = proxy.onProgress, log = proxy.log;
+ function abort(id) {
+ qq.each(handler._getXhrs(id), function(xhrId, xhr) {
+ var ajaxRequester = handler._getAjaxRequester(id, xhrId);
+ xhr.onreadystatechange = null;
+ xhr.upload.onprogress = null;
+ xhr.abort();
+ ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, blobOrProxy) {
+ if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {
+ super_.add(id, {
+ file: blobOrProxy
+ });
+ } else if (blobOrProxy instanceof qq.BlobProxy) {
+ super_.add(id, {
+ proxy: blobOrProxy
+ });
+ } else {
+ throw new Error("Passed obj is not a File, Blob, or proxy");
+ }
+ handler._initTempState(id);
+ resumeEnabled && handler._maybePrepareForResume(id);
+ },
+ expunge: function(id) {
+ abort(id);
+ handler._maybeDeletePersistedChunkData(id);
+ handler._clearXhrs(id);
+ super_.expunge(id);
+ }
+ };
+ });
+ qq.extend(this, {
+ clearCachedChunk: function(id, chunkIdx) {
+ delete handler._getFileState(id).temp.cachedChunks[chunkIdx];
+ },
+ clearXhr: function(id, chunkIdx) {
+ var tempState = handler._getFileState(id).temp;
+ if (tempState.xhrs) {
+ delete tempState.xhrs[chunkIdx];
+ }
+ if (tempState.ajaxRequesters) {
+ delete tempState.ajaxRequesters[chunkIdx];
+ }
+ },
+ finalizeChunks: function(id, responseParser) {
+ var lastChunkIdx = handler._getTotalChunks(id) - 1, xhr = handler._getXhr(id, lastChunkIdx);
+ if (responseParser) {
+ return new qq.Promise().success(responseParser(xhr), xhr);
+ }
+ return new qq.Promise().success({}, xhr);
+ },
+ getFile: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).file;
+ },
+ getProxy: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).proxy;
+ },
+ getResumableFilesData: function() {
+ var resumableFilesData = [];
+ handler._iterateResumeRecords(function(key, uploadData) {
+ handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);
+ var data = {
+ name: uploadData.name,
+ remaining: uploadData.chunking.remaining,
+ size: uploadData.size,
+ uuid: uploadData.uuid
+ };
+ if (uploadData.key) {
+ data.key = uploadData.key;
+ }
+ resumableFilesData.push(data);
+ });
+ return resumableFilesData;
+ },
+ isResumable: function(id) {
+ return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;
+ },
+ moveInProgressToRemaining: function(id, optInProgress, optRemaining) {
+ var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress, remaining = optRemaining || handler._getFileState(id).chunking.remaining;
+ if (inProgress) {
+ log(qq.format("Moving these chunks from in-progress {}, to remaining.", JSON.stringify(inProgress)));
+ inProgress.reverse();
+ qq.each(inProgress, function(idx, chunkIdx) {
+ remaining.unshift(chunkIdx);
+ });
+ inProgress.length = 0;
+ }
+ },
+ pause: function(id) {
+ if (handler.isValid(id)) {
+ log(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.", id, getName(id)));
+ handler._getFileState(id).paused = true;
+ abort(id);
+ return true;
+ }
+ },
+ reevaluateChunking: function(id) {
+ if (chunking && handler.isValid(id)) {
+ var state = handler._getFileState(id), totalChunks, i;
+ delete state.chunking;
+ state.chunking = {};
+ totalChunks = handler._getTotalChunks(id);
+ if (totalChunks > 1 || chunking.mandatory) {
+ state.chunking.enabled = true;
+ state.chunking.parts = totalChunks;
+ state.chunking.remaining = [];
+ for (i = 0; i < totalChunks; i++) {
+ state.chunking.remaining.push(i);
+ }
+ handler._initTempState(id);
+ } else {
+ state.chunking.enabled = false;
+ }
+ }
+ },
+ updateBlob: function(id, newBlob) {
+ if (handler.isValid(id)) {
+ handler._getFileState(id).file = newBlob;
+ }
+ },
+ _clearXhrs: function(id) {
+ var tempState = handler._getFileState(id).temp;
+ qq.each(tempState.ajaxRequesters, function(chunkId) {
+ delete tempState.ajaxRequesters[chunkId];
+ });
+ qq.each(tempState.xhrs, function(chunkId) {
+ delete tempState.xhrs[chunkId];
+ });
+ },
+ _createXhr: function(id, optChunkIdx) {
+ return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());
+ },
+ _getAjaxRequester: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];
+ },
+ _getChunkData: function(id, chunkIndex) {
+ var chunkSize = chunking.partSize, fileSize = getSize(id), fileOrBlob = handler.getFile(id), startBytes = chunkSize * chunkIndex, endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize, totalChunks = handler._getTotalChunks(id), cachedChunks = this._getFileState(id).temp.cachedChunks, blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);
+ cachedChunks[chunkIndex] = blob;
+ return {
+ part: chunkIndex,
+ start: startBytes,
+ end: endBytes,
+ count: totalChunks,
+ blob: blob,
+ size: endBytes - startBytes
+ };
+ },
+ _getChunkDataForCallback: function(chunkData) {
+ return {
+ partIndex: chunkData.part,
+ startByte: chunkData.start + 1,
+ endByte: chunkData.end,
+ totalParts: chunkData.count
+ };
+ },
+ _getLocalStorageId: function(id) {
+ var formatVersion = "5.0", name = getName(id), size = getSize(id), chunkSize = chunking.partSize, endpoint = getEndpoint(id);
+ return qq.format("qq{}resume{}-{}-{}-{}-{}", namespace, formatVersion, name, size, chunkSize, endpoint);
+ },
+ _getMimeType: function(id) {
+ return handler.getFile(id).type;
+ },
+ _getPersistableData: function(id) {
+ return handler._getFileState(id).chunking;
+ },
+ _getTotalChunks: function(id) {
+ if (chunking) {
+ var fileSize = getSize(id), chunkSize = chunking.partSize;
+ return Math.ceil(fileSize / chunkSize);
+ }
+ },
+ _getXhr: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.xhrs[chunkIdx];
+ },
+ _getXhrs: function(id) {
+ return handler._getFileState(id).temp.xhrs;
+ },
+ _iterateResumeRecords: function(callback) {
+ if (resumeEnabled) {
+ qq.each(localStorage, function(key, item) {
+ if (key.indexOf(qq.format("qq{}resume", namespace)) === 0) {
+ var uploadData = JSON.parse(item);
+ callback(key, uploadData);
+ }
+ });
+ }
+ },
+ _initTempState: function(id) {
+ handler._getFileState(id).temp = {
+ ajaxRequesters: {},
+ chunkProgress: {},
+ xhrs: {},
+ cachedChunks: {}
+ };
+ },
+ _markNotResumable: function(id) {
+ handler._getFileState(id).notResumable = true;
+ },
+ _maybeDeletePersistedChunkData: function(id) {
+ var localStorageId;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ if (localStorageId && localStorage.getItem(localStorageId)) {
+ localStorage.removeItem(localStorageId);
+ return true;
+ }
+ }
+ return false;
+ },
+ _maybePrepareForResume: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && state.key === undefined) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = localStorage.getItem(localStorageId);
+ if (persistedData) {
+ persistedData = JSON.parse(persistedData);
+ if (getDataByUuid(persistedData.uuid)) {
+ handler._markNotResumable(id);
+ } else {
+ log(qq.format("Identified file with ID {} and name of {} as resumable.", id, getName(id)));
+ onUuidChanged(id, persistedData.uuid);
+ state.key = persistedData.key;
+ state.chunking = persistedData.chunking;
+ state.loaded = persistedData.loaded;
+ state.attemptingResume = true;
+ handler.moveInProgressToRemaining(id);
+ }
+ }
+ }
+ },
+ _maybePersistChunkedState: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = {
+ name: getName(id),
+ size: getSize(id),
+ uuid: getUuid(id),
+ key: state.key,
+ chunking: state.chunking,
+ loaded: state.loaded,
+ lastUpdated: Date.now()
+ };
+ try {
+ localStorage.setItem(localStorageId, JSON.stringify(persistedData));
+ } catch (error) {
+ log(qq.format("Unable to save resume data for '{}' due to error: '{}'.", id, error.toString()), "warn");
+ }
+ }
+ },
+ _registerProgressHandler: function(id, chunkIdx, chunkSize) {
+ var xhr = handler._getXhr(id, chunkIdx), name = getName(id), progressCalculator = {
+ simple: function(loaded, total) {
+ var fileSize = getSize(id);
+ if (loaded === total) {
+ onProgress(id, name, fileSize, fileSize);
+ } else {
+ onProgress(id, name, loaded >= fileSize ? fileSize - 1 : loaded, fileSize);
+ }
+ },
+ chunked: function(loaded, total) {
+ var chunkProgress = handler._getFileState(id).temp.chunkProgress, totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded, loadedForRequest = loaded, totalForRequest = total, totalFileSize = getSize(id), estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize), totalLoadedForFile = totalSuccessfullyLoadedForFile;
+ chunkProgress[chunkIdx] = estActualChunkLoaded;
+ qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {
+ totalLoadedForFile += chunkLoaded;
+ });
+ onProgress(id, name, totalLoadedForFile, totalFileSize);
+ }
+ };
+ xhr.upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ var type = chunkSize == null ? "simple" : "chunked";
+ progressCalculator[type](e.loaded, e.total);
+ }
+ };
+ },
+ _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {
+ var xhrsId = optChunkIdx == null ? -1 : optChunkIdx, tempState = handler._getFileState(id).temp;
+ tempState.xhrs = tempState.xhrs || {};
+ tempState.ajaxRequesters = tempState.ajaxRequesters || {};
+ tempState.xhrs[xhrsId] = xhr;
+ if (optAjaxRequester) {
+ tempState.ajaxRequesters[xhrsId] = optAjaxRequester;
+ }
+ return xhr;
+ },
+ _removeExpiredChunkingRecords: function() {
+ var expirationDays = resume.recordsExpireIn;
+ handler._iterateResumeRecords(function(key, uploadData) {
+ var expirationDate = new Date(uploadData.lastUpdated);
+ expirationDate.setDate(expirationDate.getDate() + expirationDays);
+ if (expirationDate.getTime() <= Date.now()) {
+ log("Removing expired resume record with key " + key);
+ localStorage.removeItem(key);
+ }
+ });
+ },
+ _shouldChunkThisFile: function(id) {
+ var state = handler._getFileState(id);
+ if (!state.chunking) {
+ handler.reevaluateChunking(id);
+ }
+ return state.chunking.enabled;
+ }
+ });
+ };
+ qq.DeleteFileAjaxRequester = function(o) {
+ "use strict";
+ var requester, options = {
+ method: "DELETE",
+ uuidParamName: "qquuid",
+ endpointStore: {},
+ maxConnections: 3,
+ customHeaders: function(id) {
+ return {};
+ },
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {}
+ };
+ qq.extend(options, o);
+ function getMandatedParams() {
+ if (options.method.toUpperCase() === "POST") {
+ return {
+ _method: "DELETE"
+ };
+ }
+ return {};
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "POST", "DELETE" ],
+ method: options.method,
+ endpointStore: options.endpointStore,
+ paramsStore: options.paramsStore,
+ mandatedParams: getMandatedParams(),
+ maxConnections: options.maxConnections,
+ customHeaders: function(id) {
+ return options.customHeaders.get(id);
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendDelete: function(id, uuid, additionalMandatedParams) {
+ var additionalOptions = additionalMandatedParams || {};
+ options.log("Submitting delete file request for " + id);
+ if (options.method === "DELETE") {
+ requester.initTransport(id).withPath(uuid).withParams(additionalOptions).send();
+ } else {
+ additionalOptions[options.uuidParamName] = uuid;
+ requester.initTransport(id).withParams(additionalOptions).send();
+ }
+ }
+ });
+ };
+ (function() {
+ function detectSubsampling(img) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, canvas = document.createElement("canvas"), ctx;
+ if (iw * ih > 1024 * 1024) {
+ canvas.width = canvas.height = 1;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, -iw + 1, 0);
+ return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+ } else {
+ return false;
+ }
+ }
+ function detectVerticalSquash(img, iw, ih) {
+ var canvas = document.createElement("canvas"), sy = 0, ey = ih, py = ih, ctx, data, alpha, ratio;
+ canvas.width = 1;
+ canvas.height = ih;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, 0, 0);
+ data = ctx.getImageData(0, 0, 1, ih).data;
+ while (py > sy) {
+ alpha = data[(py - 1) * 4 + 3];
+ if (alpha === 0) {
+ ey = py;
+ } else {
+ sy = py;
+ }
+ py = ey + sy >> 1;
+ }
+ ratio = py / ih;
+ return ratio === 0 ? 1 : ratio;
+ }
+ function renderImageToDataURL(img, blob, options, doSquash) {
+ var canvas = document.createElement("canvas"), mime = options.mime || "image/jpeg", promise = new qq.Promise();
+ renderImageToCanvas(img, blob, canvas, options, doSquash).then(function() {
+ promise.success(canvas.toDataURL(mime, options.quality || .8));
+ });
+ return promise;
+ }
+ function maybeCalculateDownsampledDimensions(spec) {
+ var maxPixels = 5241e3;
+ if (!qq.ios()) {
+ throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");
+ }
+ if (spec.origHeight * spec.origWidth > maxPixels) {
+ return {
+ newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),
+ newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))
+ };
+ }
+ }
+ function renderImageToCanvas(img, blob, canvas, options, doSquash) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, width = options.width, height = options.height, ctx = canvas.getContext("2d"), promise = new qq.Promise(), modifiedDimensions;
+ ctx.save();
+ if (options.resize) {
+ return renderImageToCanvasWithCustomResizer({
+ blob: blob,
+ canvas: canvas,
+ image: img,
+ imageHeight: ih,
+ imageWidth: iw,
+ orientation: options.orientation,
+ resize: options.resize,
+ targetHeight: height,
+ targetWidth: width
+ });
+ }
+ if (!qq.supportedFeatures.unlimitedScaledImageSize) {
+ modifiedDimensions = maybeCalculateDownsampledDimensions({
+ origWidth: width,
+ origHeight: height
+ });
+ if (modifiedDimensions) {
+ qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h", width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight), "warn");
+ width = modifiedDimensions.newWidth;
+ height = modifiedDimensions.newHeight;
+ }
+ }
+ transformCoordinate(canvas, width, height, options.orientation);
+ if (qq.ios()) {
+ (function() {
+ if (detectSubsampling(img)) {
+ iw /= 2;
+ ih /= 2;
+ }
+ var d = 1024, tmpCanvas = document.createElement("canvas"), vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1, dw = Math.ceil(d * width / iw), dh = Math.ceil(d * height / ih / vertSquashRatio), sy = 0, dy = 0, tmpCtx, sx, dx;
+ tmpCanvas.width = tmpCanvas.height = d;
+ tmpCtx = tmpCanvas.getContext("2d");
+ while (sy < ih) {
+ sx = 0;
+ dx = 0;
+ while (sx < iw) {
+ tmpCtx.clearRect(0, 0, d, d);
+ tmpCtx.drawImage(img, -sx, -sy);
+ ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);
+ sx += d;
+ dx += dw;
+ }
+ sy += d;
+ dy += dh;
+ }
+ ctx.restore();
+ tmpCanvas = tmpCtx = null;
+ })();
+ } else {
+ ctx.drawImage(img, 0, 0, width, height);
+ }
+ canvas.qqImageRendered && canvas.qqImageRendered();
+ promise.success();
+ return promise;
+ }
+ function renderImageToCanvasWithCustomResizer(resizeInfo) {
+ var blob = resizeInfo.blob, image = resizeInfo.image, imageHeight = resizeInfo.imageHeight, imageWidth = resizeInfo.imageWidth, orientation = resizeInfo.orientation, promise = new qq.Promise(), resize = resizeInfo.resize, sourceCanvas = document.createElement("canvas"), sourceCanvasContext = sourceCanvas.getContext("2d"), targetCanvas = resizeInfo.canvas, targetHeight = resizeInfo.targetHeight, targetWidth = resizeInfo.targetWidth;
+ transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);
+ targetCanvas.height = targetHeight;
+ targetCanvas.width = targetWidth;
+ sourceCanvasContext.drawImage(image, 0, 0);
+ resize({
+ blob: blob,
+ height: targetHeight,
+ image: image,
+ sourceCanvas: sourceCanvas,
+ targetCanvas: targetCanvas,
+ width: targetWidth
+ }).then(function success() {
+ targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();
+ promise.success();
+ }, promise.failure);
+ return promise;
+ }
+ function transformCoordinate(canvas, width, height, orientation) {
+ switch (orientation) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ canvas.width = height;
+ canvas.height = width;
+ break;
+
+ default:
+ canvas.width = width;
+ canvas.height = height;
+ }
+ var ctx = canvas.getContext("2d");
+ switch (orientation) {
+ case 2:
+ ctx.translate(width, 0);
+ ctx.scale(-1, 1);
+ break;
+
+ case 3:
+ ctx.translate(width, height);
+ ctx.rotate(Math.PI);
+ break;
+
+ case 4:
+ ctx.translate(0, height);
+ ctx.scale(1, -1);
+ break;
+
+ case 5:
+ ctx.rotate(.5 * Math.PI);
+ ctx.scale(1, -1);
+ break;
+
+ case 6:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(0, -height);
+ break;
+
+ case 7:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(width, -height);
+ ctx.scale(-1, 1);
+ break;
+
+ case 8:
+ ctx.rotate(-.5 * Math.PI);
+ ctx.translate(-width, 0);
+ break;
+
+ default:
+ break;
+ }
+ }
+ function MegaPixImage(srcImage, errorCallback) {
+ var self = this;
+ if (window.Blob && srcImage instanceof Blob) {
+ (function() {
+ var img = new Image(), URL = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (!URL) {
+ throw Error("No createObjectURL function found to create blob url");
+ }
+ img.src = URL.createObjectURL(srcImage);
+ self.blob = srcImage;
+ srcImage = img;
+ })();
+ }
+ if (!srcImage.naturalWidth && !srcImage.naturalHeight) {
+ srcImage.onload = function() {
+ var listeners = self.imageLoadListeners;
+ if (listeners) {
+ self.imageLoadListeners = null;
+ setTimeout(function() {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i]();
+ }
+ }, 0);
+ }
+ };
+ srcImage.onerror = errorCallback;
+ this.imageLoadListeners = [];
+ }
+ this.srcImage = srcImage;
+ }
+ MegaPixImage.prototype.render = function(target, options) {
+ options = options || {};
+ var self = this, imgWidth = this.srcImage.naturalWidth, imgHeight = this.srcImage.naturalHeight, width = options.width, height = options.height, maxWidth = options.maxWidth, maxHeight = options.maxHeight, doSquash = !this.blob || this.blob.type === "image/jpeg", tagName = target.tagName.toLowerCase(), opt;
+ if (this.imageLoadListeners) {
+ this.imageLoadListeners.push(function() {
+ self.render(target, options);
+ });
+ return;
+ }
+ if (width && !height) {
+ height = imgHeight * width / imgWidth << 0;
+ } else if (height && !width) {
+ width = imgWidth * height / imgHeight << 0;
+ } else {
+ width = imgWidth;
+ height = imgHeight;
+ }
+ if (maxWidth && width > maxWidth) {
+ width = maxWidth;
+ height = imgHeight * width / imgWidth << 0;
+ }
+ if (maxHeight && height > maxHeight) {
+ height = maxHeight;
+ width = imgWidth * height / imgHeight << 0;
+ }
+ opt = {
+ width: width,
+ height: height
+ }, qq.each(options, function(optionsKey, optionsValue) {
+ opt[optionsKey] = optionsValue;
+ });
+ if (tagName === "img") {
+ (function() {
+ var oldTargetSrc = target.src;
+ renderImageToDataURL(self.srcImage, self.blob, opt, doSquash).then(function(dataUri) {
+ target.src = dataUri;
+ oldTargetSrc === target.src && target.onload();
+ });
+ })();
+ } else if (tagName === "canvas") {
+ renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);
+ }
+ if (typeof this.onrender === "function") {
+ this.onrender(target);
+ }
+ };
+ qq.MegaPixImage = MegaPixImage;
+ })();
+ qq.ImageGenerator = function(log) {
+ "use strict";
+ function isImg(el) {
+ return el.tagName.toLowerCase() === "img";
+ }
+ function isCanvas(el) {
+ return el.tagName.toLowerCase() === "canvas";
+ }
+ function isImgCorsSupported() {
+ return new Image().crossOrigin !== undefined;
+ }
+ function isCanvasSupported() {
+ var canvas = document.createElement("canvas");
+ return canvas.getContext && canvas.getContext("2d");
+ }
+ function determineMimeOfFileName(nameWithPath) {
+ var pathSegments = nameWithPath.split("/"), name = pathSegments[pathSegments.length - 1].split("?")[0], extension = qq.getExtension(name);
+ extension = extension && extension.toLowerCase();
+ switch (extension) {
+ case "jpeg":
+ case "jpg":
+ return "image/jpeg";
+
+ case "png":
+ return "image/png";
+
+ case "bmp":
+ return "image/bmp";
+
+ case "gif":
+ return "image/gif";
+
+ case "tiff":
+ case "tif":
+ return "image/tiff";
+ }
+ }
+ function isCrossOrigin(url) {
+ var targetAnchor = document.createElement("a"), targetProtocol, targetHostname, targetPort;
+ targetAnchor.href = url;
+ targetProtocol = targetAnchor.protocol;
+ targetPort = targetAnchor.port;
+ targetHostname = targetAnchor.hostname;
+ if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {
+ return true;
+ }
+ if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {
+ return true;
+ }
+ if (targetPort !== window.location.port && !qq.ie()) {
+ return true;
+ }
+ return false;
+ }
+ function registerImgLoadListeners(img, promise) {
+ img.onload = function() {
+ img.onload = null;
+ img.onerror = null;
+ promise.success(img);
+ };
+ img.onerror = function() {
+ img.onload = null;
+ img.onerror = null;
+ log("Problem drawing thumbnail!", "error");
+ promise.failure(img, "Problem drawing thumbnail!");
+ };
+ }
+ function registerCanvasDrawImageListener(canvas, promise) {
+ canvas.qqImageRendered = function() {
+ promise.success(canvas);
+ };
+ }
+ function registerThumbnailRenderedListener(imgOrCanvas, promise) {
+ var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);
+ if (isImg(imgOrCanvas)) {
+ registerImgLoadListeners(imgOrCanvas, promise);
+ } else if (isCanvas(imgOrCanvas)) {
+ registerCanvasDrawImageListener(imgOrCanvas, promise);
+ } else {
+ promise.failure(imgOrCanvas);
+ log(qq.format("Element container of type {} is not supported!", imgOrCanvas.tagName), "error");
+ }
+ return registered;
+ }
+ function draw(fileOrBlob, container, options) {
+ var drawPreview = new qq.Promise(), identifier = new qq.Identify(fileOrBlob, log), maxSize = options.maxSize, orient = options.orient == null ? true : options.orient, megapixErrorHandler = function() {
+ container.onerror = null;
+ container.onload = null;
+ log("Could not render preview, file may be too large!", "error");
+ drawPreview.failure(container, "Browser cannot render image!");
+ };
+ identifier.isPreviewable().then(function(mime) {
+ var dummyExif = {
+ parse: function() {
+ return new qq.Promise().success();
+ }
+ }, exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif, mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);
+ if (registerThumbnailRenderedListener(container, drawPreview)) {
+ exif.parse().then(function(exif) {
+ var orientation = exif && exif.Orientation;
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ orientation: orientation,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ }, function(failureMsg) {
+ log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", failureMsg));
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ });
+ }
+ }, function() {
+ log("Not previewable");
+ drawPreview.failure(container, "Not previewable");
+ });
+ return drawPreview;
+ }
+ function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {
+ var tempImg = new Image(), tempImgRender = new qq.Promise();
+ registerThumbnailRenderedListener(tempImg, tempImgRender);
+ if (isCrossOrigin(url)) {
+ tempImg.crossOrigin = "anonymous";
+ }
+ tempImg.src = url;
+ tempImgRender.then(function rendered() {
+ registerThumbnailRenderedListener(canvasOrImg, draw);
+ var mpImg = new qq.MegaPixImage(tempImg);
+ mpImg.render(canvasOrImg, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: determineMimeOfFileName(url),
+ resize: customResizeFunction
+ });
+ }, draw.failure);
+ }
+ function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {
+ registerThumbnailRenderedListener(img, draw);
+ qq(img).css({
+ maxWidth: maxSize + "px",
+ maxHeight: maxSize + "px"
+ });
+ img.src = url;
+ }
+ function drawFromUrl(url, container, options) {
+ var draw = new qq.Promise(), scale = options.scale, maxSize = scale ? options.maxSize : null;
+ if (scale && isImg(container)) {
+ if (isCanvasSupported()) {
+ if (isCrossOrigin(url) && !isImgCorsSupported()) {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ } else {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ }
+ } else {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ }
+ } else if (isCanvas(container)) {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ } else if (registerThumbnailRenderedListener(container, draw)) {
+ container.src = url;
+ }
+ return draw;
+ }
+ qq.extend(this, {
+ generate: function(fileBlobOrUrl, container, options) {
+ if (qq.isString(fileBlobOrUrl)) {
+ log("Attempting to update thumbnail based on server response.");
+ return drawFromUrl(fileBlobOrUrl, container, options || {});
+ } else {
+ log("Attempting to draw client-side image preview.");
+ return draw(fileBlobOrUrl, container, options || {});
+ }
+ }
+ });
+ this._testing = {};
+ this._testing.isImg = isImg;
+ this._testing.isCanvas = isCanvas;
+ this._testing.isCrossOrigin = isCrossOrigin;
+ this._testing.determineMimeOfFileName = determineMimeOfFileName;
+ };
+ qq.Exif = function(fileOrBlob, log) {
+ "use strict";
+ var TAG_IDS = [ 274 ], TAG_INFO = {
+ 274: {
+ name: "Orientation",
+ bytes: 2
+ }
+ };
+ function parseLittleEndian(hex) {
+ var result = 0, pow = 0;
+ while (hex.length > 0) {
+ result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);
+ hex = hex.substring(2, hex.length);
+ pow += 8;
+ }
+ return result;
+ }
+ function seekToApp1(offset, promise) {
+ var theOffset = offset, thePromise = promise;
+ if (theOffset === undefined) {
+ theOffset = 2;
+ thePromise = new qq.Promise();
+ }
+ qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {
+ var match = /^ffe([0-9])/.exec(hex), segmentLength;
+ if (match) {
+ if (match[1] !== "1") {
+ segmentLength = parseInt(hex.slice(4, 8), 16);
+ seekToApp1(theOffset + segmentLength + 2, thePromise);
+ } else {
+ thePromise.success(theOffset);
+ }
+ } else {
+ thePromise.failure("No EXIF header to be found!");
+ }
+ });
+ return thePromise;
+ }
+ function getApp1Offset() {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {
+ if (hex.indexOf("ffd8") !== 0) {
+ promise.failure("Not a valid JPEG!");
+ } else {
+ seekToApp1().then(function(offset) {
+ promise.success(offset);
+ }, function(error) {
+ promise.failure(error);
+ });
+ }
+ });
+ return promise;
+ }
+ function isLittleEndian(app1Start) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {
+ promise.success(hex === "4949");
+ });
+ return promise;
+ }
+ function getDirEntryCount(app1Start, littleEndian) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {
+ if (littleEndian) {
+ return promise.success(parseLittleEndian(hex));
+ } else {
+ promise.success(parseInt(hex, 16));
+ }
+ });
+ return promise;
+ }
+ function getIfd(app1Start, dirEntries) {
+ var offset = app1Start + 20, bytes = dirEntries * 12;
+ return qq.readBlobToHex(fileOrBlob, offset, bytes);
+ }
+ function getDirEntries(ifdHex) {
+ var entries = [], offset = 0;
+ while (offset + 24 <= ifdHex.length) {
+ entries.push(ifdHex.slice(offset, offset + 24));
+ offset += 24;
+ }
+ return entries;
+ }
+ function getTagValues(littleEndian, dirEntries) {
+ var TAG_VAL_OFFSET = 16, tagsToFind = qq.extend([], TAG_IDS), vals = {};
+ qq.each(dirEntries, function(idx, entry) {
+ var idHex = entry.slice(0, 4), id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16), tagsToFindIdx = tagsToFind.indexOf(id), tagValHex, tagName, tagValLength;
+ if (tagsToFindIdx >= 0) {
+ tagName = TAG_INFO[id].name;
+ tagValLength = TAG_INFO[id].bytes;
+ tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + tagValLength * 2);
+ vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);
+ tagsToFind.splice(tagsToFindIdx, 1);
+ }
+ if (tagsToFind.length === 0) {
+ return false;
+ }
+ });
+ return vals;
+ }
+ qq.extend(this, {
+ parse: function() {
+ var parser = new qq.Promise(), onParseFailure = function(message) {
+ log(qq.format("EXIF header parse failed: '{}' ", message));
+ parser.failure(message);
+ };
+ getApp1Offset().then(function(app1Offset) {
+ log(qq.format("Moving forward with EXIF header parsing for '{}'", fileOrBlob.name === undefined ? "blob" : fileOrBlob.name));
+ isLittleEndian(app1Offset).then(function(littleEndian) {
+ log(qq.format("EXIF Byte order is {} endian", littleEndian ? "little" : "big"));
+ getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {
+ log(qq.format("Found {} APP1 directory entries", dirEntryCount));
+ getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {
+ var dirEntries = getDirEntries(ifdHex), tagValues = getTagValues(littleEndian, dirEntries);
+ log("Successfully parsed some EXIF tags");
+ parser.success(tagValues);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ return parser;
+ }
+ });
+ this._testing = {};
+ this._testing.parseLittleEndian = parseLittleEndian;
+ };
+ qq.Identify = function(fileOrBlob, log) {
+ "use strict";
+ function isIdentifiable(magicBytes, questionableBytes) {
+ var identifiable = false, magicBytesEntries = [].concat(magicBytes);
+ qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {
+ if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {
+ identifiable = true;
+ return false;
+ }
+ });
+ return identifiable;
+ }
+ qq.extend(this, {
+ isPreviewable: function() {
+ var self = this, identifier = new qq.Promise(), previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ log(qq.format("Attempting to determine if {} can be rendered in this browser", name));
+ log("First pass: check type attribute of blob object.");
+ if (this.isPreviewableSync()) {
+ log("Second pass: check for magic bytes in file header.");
+ qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {
+ qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {
+ if (isIdentifiable(bytes, hex)) {
+ if (mime !== "image/tiff" || qq.supportedFeatures.tiffPreviews) {
+ previewable = true;
+ identifier.success(mime);
+ }
+ return false;
+ }
+ });
+ log(qq.format("'{}' is {} able to be rendered in this browser", name, previewable ? "" : "NOT"));
+ if (!previewable) {
+ identifier.failure();
+ }
+ }, function() {
+ log("Error reading file w/ name '" + name + "'. Not able to be rendered in this browser.");
+ identifier.failure();
+ });
+ } else {
+ identifier.failure();
+ }
+ return identifier;
+ },
+ isPreviewableSync: function() {
+ var fileMime = fileOrBlob.type, isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0, previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ if (isRecognizedImage) {
+ if (fileMime === "image/tiff") {
+ previewable = qq.supportedFeatures.tiffPreviews;
+ } else {
+ previewable = true;
+ }
+ }
+ !previewable && log(name + " is not previewable in this browser per the blob's type attr");
+ return previewable;
+ }
+ });
+ };
+ qq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {
+ "image/jpeg": "ffd8ff",
+ "image/gif": "474946",
+ "image/png": "89504e",
+ "image/bmp": "424d",
+ "image/tiff": [ "49492a00", "4d4d002a" ]
+ };
+ qq.ImageValidation = function(blob, log) {
+ "use strict";
+ function hasNonZeroLimits(limits) {
+ var atLeastOne = false;
+ qq.each(limits, function(limit, value) {
+ if (value > 0) {
+ atLeastOne = true;
+ return false;
+ }
+ });
+ return atLeastOne;
+ }
+ function getWidthHeight() {
+ var sizeDetermination = new qq.Promise();
+ new qq.Identify(blob, log).isPreviewable().then(function() {
+ var image = new Image(), url = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (url) {
+ image.onerror = function() {
+ log("Cannot determine dimensions for image. May be too large.", "error");
+ sizeDetermination.failure();
+ };
+ image.onload = function() {
+ sizeDetermination.success({
+ width: this.width,
+ height: this.height
+ });
+ };
+ image.src = url.createObjectURL(blob);
+ } else {
+ log("No createObjectURL function available to generate image URL!", "error");
+ sizeDetermination.failure();
+ }
+ }, sizeDetermination.failure);
+ return sizeDetermination;
+ }
+ function getFailingLimit(limits, dimensions) {
+ var failingLimit;
+ qq.each(limits, function(limitName, limitValue) {
+ if (limitValue > 0) {
+ var limitMatcher = /(max|min)(Width|Height)/.exec(limitName), dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1), actualValue = dimensions[dimensionPropName];
+ switch (limitMatcher[1]) {
+ case "min":
+ if (actualValue < limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+
+ case "max":
+ if (actualValue > limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+ }
+ }
+ });
+ return failingLimit;
+ }
+ this.validate = function(limits) {
+ var validationEffort = new qq.Promise();
+ log("Attempting to validate image.");
+ if (hasNonZeroLimits(limits)) {
+ getWidthHeight().then(function(dimensions) {
+ var failingLimit = getFailingLimit(limits, dimensions);
+ if (failingLimit) {
+ validationEffort.failure(failingLimit);
+ } else {
+ validationEffort.success();
+ }
+ }, validationEffort.success);
+ } else {
+ validationEffort.success();
+ }
+ return validationEffort;
+ };
+ };
+ qq.Session = function(spec) {
+ "use strict";
+ var options = {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ cors: {},
+ addFileRecord: function(sessionData) {},
+ log: function(message, level) {}
+ };
+ qq.extend(options, spec, true);
+ function isJsonResponseValid(response) {
+ if (qq.isArray(response)) {
+ return true;
+ }
+ options.log("Session response is not an array.", "error");
+ }
+ function handleFileItems(fileItems, success, xhrOrXdr, promise) {
+ var someItemsIgnored = false;
+ success = success && isJsonResponseValid(fileItems);
+ if (success) {
+ qq.each(fileItems, function(idx, fileItem) {
+ if (fileItem.uuid == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid UUID - ignoring.", idx), "error");
+ } else if (fileItem.name == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid name - ignoring.", idx), "error");
+ } else {
+ try {
+ options.addFileRecord(fileItem);
+ return true;
+ } catch (err) {
+ someItemsIgnored = true;
+ options.log(err.message, "error");
+ }
+ }
+ return false;
+ });
+ }
+ promise[success && !someItemsIgnored ? "success" : "failure"](fileItems, xhrOrXdr);
+ }
+ this.refresh = function() {
+ var refreshEffort = new qq.Promise(), refreshCompleteCallback = function(response, success, xhrOrXdr) {
+ handleFileItems(response, success, xhrOrXdr, refreshEffort);
+ }, requesterOptions = qq.extend({}, options), requester = new qq.SessionAjaxRequester(qq.extend(requesterOptions, {
+ onComplete: refreshCompleteCallback
+ }));
+ requester.queryServer();
+ return refreshEffort;
+ };
+ };
+ qq.SessionAjaxRequester = function(spec) {
+ "use strict";
+ var requester, options = {
+ endpoint: null,
+ customHeaders: {},
+ params: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ onComplete: function(response, success, xhrOrXdr) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, spec);
+ function onComplete(id, xhrOrXdr, isError) {
+ var response = null;
+ if (xhrOrXdr.responseText != null) {
+ try {
+ response = qq.parseJson(xhrOrXdr.responseText);
+ } catch (err) {
+ options.log("Problem parsing session response: " + err.message, "error");
+ isError = true;
+ }
+ }
+ options.onComplete(response, !isError, xhrOrXdr);
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: onComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ queryServer: function() {
+ var params = qq.extend({}, options.params);
+ options.log("Session query request.");
+ requester.initTransport("sessionRefresh").withParams(params).withCacheBuster().send();
+ }
+ });
+ };
+ qq.Scaler = function(spec, log) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizer, includeOriginal = spec.sendOriginal, orient = spec.orient, defaultType = spec.defaultType, defaultQuality = spec.defaultQuality / 100, failedToScaleText = spec.failureText, includeExif = spec.includeExif, sizes = this._getSortedSizes(spec.sizes);
+ qq.extend(this, {
+ enabled: qq.supportedFeatures.scaling && sizes.length > 0,
+ getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {
+ var self = this, records = [], originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData, identifier = new qq.Identify(originalBlob, log);
+ if (identifier.isPreviewableSync()) {
+ qq.each(sizes, function(idx, sizeRecord) {
+ var outputType = self._determineOutputType({
+ defaultType: defaultType,
+ requestedType: sizeRecord.type,
+ refType: originalBlob.type
+ });
+ records.push({
+ uuid: qq.getUniqueId(),
+ name: self._getName(originalFileName, {
+ name: sizeRecord.name,
+ type: outputType,
+ refType: originalBlob.type
+ }),
+ blob: new qq.BlobProxy(originalBlob, qq.bind(self._generateScaledImage, self, {
+ customResizeFunction: customResizeFunction,
+ maxSize: sizeRecord.maxSize,
+ orient: orient,
+ type: outputType,
+ quality: defaultQuality,
+ failedText: failedToScaleText,
+ includeExif: includeExif,
+ log: log
+ }))
+ });
+ });
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: includeOriginal ? originalBlob : null
+ });
+ } else {
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: originalBlob
+ });
+ }
+ return records;
+ },
+ handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {
+ var self = this, buttonId = file.qqButtonId || file.blob && file.blob.qqButtonId, scaledIds = [], originalId = null, addFileToHandler = api.addFileToHandler, uploadData = api.uploadData, paramsStore = api.paramsStore, proxyGroupId = qq.getUniqueId();
+ qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {
+ var blobSize = record.size, id;
+ if (record.blob instanceof qq.BlobProxy) {
+ blobSize = -1;
+ }
+ id = uploadData.addFile({
+ uuid: record.uuid,
+ name: record.name,
+ size: blobSize,
+ batchId: batchId,
+ proxyGroupId: proxyGroupId
+ });
+ if (record.blob instanceof qq.BlobProxy) {
+ scaledIds.push(id);
+ } else {
+ originalId = id;
+ }
+ if (record.blob) {
+ addFileToHandler(id, record.blob);
+ fileList.push({
+ id: id,
+ file: record.blob
+ });
+ } else {
+ uploadData.setStatus(id, qq.status.REJECTED);
+ }
+ });
+ if (originalId !== null) {
+ qq.each(scaledIds, function(idx, scaledId) {
+ var params = {
+ qqparentuuid: uploadData.retrieve({
+ id: originalId
+ }).uuid,
+ qqparentsize: uploadData.retrieve({
+ id: originalId
+ }).size
+ };
+ params[uuidParamName] = uploadData.retrieve({
+ id: scaledId
+ }).uuid;
+ uploadData.setParentId(scaledId, originalId);
+ paramsStore.addReadOnly(scaledId, params);
+ });
+ if (scaledIds.length) {
+ (function() {
+ var param = {};
+ param[uuidParamName] = uploadData.retrieve({
+ id: originalId
+ }).uuid;
+ paramsStore.addReadOnly(originalId, param);
+ })();
+ }
+ }
+ }
+ });
+ };
+ qq.extend(qq.Scaler.prototype, {
+ scaleImage: function(id, specs, api) {
+ "use strict";
+ if (!qq.supportedFeatures.scaling) {
+ throw new qq.Error("Scaling is not supported in this browser!");
+ }
+ var scalingEffort = new qq.Promise(), log = api.log, file = api.getFile(id), uploadData = api.uploadData.retrieve({
+ id: id
+ }), name = uploadData && uploadData.name, uuid = uploadData && uploadData.uuid, scalingOptions = {
+ customResizer: specs.customResizer,
+ sendOriginal: false,
+ orient: specs.orient,
+ defaultType: specs.type || null,
+ defaultQuality: specs.quality,
+ failedToScaleText: "Unable to scale",
+ sizes: [ {
+ name: "",
+ maxSize: specs.maxSize
+ } ]
+ }, scaler = new qq.Scaler(scalingOptions, log);
+ if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {
+ scalingEffort.failure();
+ log("Could not generate requested scaled image for " + id + ". " + "Scaling is either not possible in this browser, or the file could not be located.", "error");
+ } else {
+ qq.bind(function() {
+ var record = scaler.getFileRecords(uuid, name, file)[0];
+ if (record && record.blob instanceof qq.BlobProxy) {
+ record.blob.create().then(scalingEffort.success, scalingEffort.failure);
+ } else {
+ log(id + " is not a scalable image!", "error");
+ scalingEffort.failure();
+ }
+ }, this)();
+ }
+ return scalingEffort;
+ },
+ _determineOutputType: function(spec) {
+ "use strict";
+ var requestedType = spec.requestedType, defaultType = spec.defaultType, referenceType = spec.refType;
+ if (!defaultType && !requestedType) {
+ if (referenceType !== "image/jpeg") {
+ return "image/png";
+ }
+ return referenceType;
+ }
+ if (!requestedType) {
+ return defaultType;
+ }
+ if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {
+ if (requestedType === "image/tiff") {
+ return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;
+ }
+ return requestedType;
+ }
+ return defaultType;
+ },
+ _getName: function(originalName, scaledVersionProperties) {
+ "use strict";
+ var startOfExt = originalName.lastIndexOf("."), versionType = scaledVersionProperties.type || "image/png", referenceType = scaledVersionProperties.refType, scaledName = "", scaledExt = qq.getExtension(originalName), nameAppendage = "";
+ if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {
+ nameAppendage = " (" + scaledVersionProperties.name + ")";
+ }
+ if (startOfExt >= 0) {
+ scaledName = originalName.substr(0, startOfExt);
+ if (referenceType !== versionType) {
+ scaledExt = versionType.split("/")[1];
+ }
+ scaledName += nameAppendage + "." + scaledExt;
+ } else {
+ scaledName = originalName + nameAppendage;
+ }
+ return scaledName;
+ },
+ _getSortedSizes: function(sizes) {
+ "use strict";
+ sizes = qq.extend([], sizes);
+ return sizes.sort(function(a, b) {
+ if (a.maxSize > b.maxSize) {
+ return 1;
+ }
+ if (a.maxSize < b.maxSize) {
+ return -1;
+ }
+ return 0;
+ });
+ },
+ _generateScaledImage: function(spec, sourceFile) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizeFunction, log = spec.log, maxSize = spec.maxSize, orient = spec.orient, type = spec.type, quality = spec.quality, failedText = spec.failedText, includeExif = spec.includeExif && sourceFile.type === "image/jpeg" && type === "image/jpeg", scalingEffort = new qq.Promise(), imageGenerator = new qq.ImageGenerator(log), canvas = document.createElement("canvas");
+ log("Attempting to generate scaled version for " + sourceFile.name);
+ imageGenerator.generate(sourceFile, canvas, {
+ maxSize: maxSize,
+ orient: orient,
+ customResizeFunction: customResizeFunction
+ }).then(function() {
+ var scaledImageDataUri = canvas.toDataURL(type, quality), signalSuccess = function() {
+ log("Success generating scaled version for " + sourceFile.name);
+ var blob = qq.dataUriToBlob(scaledImageDataUri);
+ scalingEffort.success(blob);
+ };
+ if (includeExif) {
+ self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {
+ scaledImageDataUri = scaledImageDataUriWithExif;
+ signalSuccess();
+ }, function() {
+ log("Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.", "error");
+ signalSuccess();
+ });
+ } else {
+ signalSuccess();
+ }
+ }, function() {
+ log("Failed attempt to generate scaled version for " + sourceFile.name, "error");
+ scalingEffort.failure(failedText);
+ });
+ return scalingEffort;
+ },
+ _insertExifHeader: function(originalImage, scaledImageDataUri, log) {
+ "use strict";
+ var reader = new FileReader(), insertionEffort = new qq.Promise(), originalImageDataUri = "";
+ reader.onload = function() {
+ originalImageDataUri = reader.result;
+ insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));
+ };
+ reader.onerror = function() {
+ log("Problem reading " + originalImage.name + " during attempt to transfer EXIF data to scaled version.", "error");
+ insertionEffort.failure();
+ };
+ reader.readAsDataURL(originalImage);
+ return insertionEffort;
+ },
+ _dataUriToBlob: function(dataUri) {
+ "use strict";
+ var byteString, mimeString, arrayBuffer, intArray;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return this._createBlob(arrayBuffer, mimeString);
+ },
+ _createBlob: function(data, mime) {
+ "use strict";
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }
+ });
+ qq.ExifRestorer = function() {
+ var ExifRestorer = {};
+ ExifRestorer.KEY_STR = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + "ghijklmnopqrstuv" + "wxyz0123456789+/" + "=";
+ ExifRestorer.encode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0;
+ do {
+ chr1 = input[i++];
+ chr2 = input[i++];
+ chr3 = input[i++];
+ enc1 = chr1 >> 2;
+ enc2 = (chr1 & 3) << 4 | chr2 >> 4;
+ enc3 = (chr2 & 15) << 2 | chr3 >> 6;
+ enc4 = chr3 & 63;
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+ output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4);
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return output;
+ };
+ ExifRestorer.restore = function(origFileBase64, resizedFileBase64) {
+ var expectedBase64Header = "data:image/jpeg;base64,";
+ if (!origFileBase64.match(expectedBase64Header)) {
+ return resizedFileBase64;
+ }
+ var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, ""));
+ var segments = this.slice2Segments(rawImage);
+ var image = this.exifManipulation(resizedFileBase64, segments);
+ return expectedBase64Header + this.encode64(image);
+ };
+ ExifRestorer.exifManipulation = function(resizedFileBase64, segments) {
+ var exifArray = this.getExifArray(segments), newImageArray = this.insertExif(resizedFileBase64, exifArray), aBuffer = new Uint8Array(newImageArray);
+ return aBuffer;
+ };
+ ExifRestorer.getExifArray = function(segments) {
+ var seg;
+ for (var x = 0; x < segments.length; x++) {
+ seg = segments[x];
+ if (seg[0] == 255 & seg[1] == 225) {
+ return seg;
+ }
+ }
+ return [];
+ };
+ ExifRestorer.insertExif = function(resizedFileBase64, exifArray) {
+ var imageData = resizedFileBase64.replace("data:image/jpeg;base64,", ""), buf = this.decode64(imageData), separatePoint = buf.indexOf(255, 3), mae = buf.slice(0, separatePoint), ato = buf.slice(separatePoint), array = mae;
+ array = array.concat(exifArray);
+ array = array.concat(ato);
+ return array;
+ };
+ ExifRestorer.slice2Segments = function(rawImageArray) {
+ var head = 0, segments = [];
+ while (1) {
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218) {
+ break;
+ }
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216) {
+ head += 2;
+ } else {
+ var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3], endPoint = head + length + 2, seg = rawImageArray.slice(head, endPoint);
+ segments.push(seg);
+ head = endPoint;
+ }
+ if (head > rawImageArray.length) {
+ break;
+ }
+ }
+ return segments;
+ };
+ ExifRestorer.decode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0, buf = [];
+ var base64test = /[^A-Za-z0-9\+\/\=]/g;
+ if (base64test.exec(input)) {
+ throw new Error("There were invalid base64 characters in the input text. " + "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");
+ }
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+ do {
+ enc1 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc2 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc3 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc4 = this.KEY_STR.indexOf(input.charAt(i++));
+ chr1 = enc1 << 2 | enc2 >> 4;
+ chr2 = (enc2 & 15) << 4 | enc3 >> 2;
+ chr3 = (enc3 & 3) << 6 | enc4;
+ buf.push(chr1);
+ if (enc3 != 64) {
+ buf.push(chr2);
+ }
+ if (enc4 != 64) {
+ buf.push(chr3);
+ }
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return buf;
+ };
+ return ExifRestorer;
+ }();
+ qq.TotalProgress = function(callback, getSize) {
+ "use strict";
+ var perFileProgress = {}, totalLoaded = 0, totalSize = 0, lastLoadedSent = -1, lastTotalSent = -1, callbackProxy = function(loaded, total) {
+ if (loaded !== lastLoadedSent || total !== lastTotalSent) {
+ callback(loaded, total);
+ }
+ lastLoadedSent = loaded;
+ lastTotalSent = total;
+ }, noRetryableFiles = function(failed, retryable) {
+ var none = true;
+ qq.each(failed, function(idx, failedId) {
+ if (qq.indexOf(retryable, failedId) >= 0) {
+ none = false;
+ return false;
+ }
+ });
+ return none;
+ }, onCancel = function(id) {
+ updateTotalProgress(id, -1, -1);
+ delete perFileProgress[id];
+ }, onAllComplete = function(successful, failed, retryable) {
+ if (failed.length === 0 || noRetryableFiles(failed, retryable)) {
+ callbackProxy(totalSize, totalSize);
+ this.reset();
+ }
+ }, onNew = function(id) {
+ var size = getSize(id);
+ if (size > 0) {
+ updateTotalProgress(id, 0, size);
+ perFileProgress[id] = {
+ loaded: 0,
+ total: size
+ };
+ }
+ }, updateTotalProgress = function(id, newLoaded, newTotal) {
+ var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0, oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;
+ if (newLoaded === -1 && newTotal === -1) {
+ totalLoaded -= oldLoaded;
+ totalSize -= oldTotal;
+ } else {
+ if (newLoaded) {
+ totalLoaded += newLoaded - oldLoaded;
+ }
+ if (newTotal) {
+ totalSize += newTotal - oldTotal;
+ }
+ }
+ callbackProxy(totalLoaded, totalSize);
+ };
+ qq.extend(this, {
+ onAllComplete: onAllComplete,
+ onStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {
+ onCancel(id);
+ } else if (newStatus === qq.status.SUBMITTING) {
+ onNew(id);
+ }
+ },
+ onIndividualProgress: function(id, loaded, total) {
+ updateTotalProgress(id, loaded, total);
+ perFileProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onNewSize: function(id) {
+ onNew(id);
+ },
+ reset: function() {
+ perFileProgress = {};
+ totalLoaded = 0;
+ totalSize = 0;
+ }
+ });
+ };
+ qq.PasteSupport = function(o) {
+ "use strict";
+ var options, detachPasteHandler;
+ options = {
+ targetElement: null,
+ callbacks: {
+ log: function(message, level) {},
+ pasteReceived: function(blob) {}
+ }
+ };
+ function isImage(item) {
+ return item.type && item.type.indexOf("image/") === 0;
+ }
+ function registerPasteHandler() {
+ detachPasteHandler = qq(options.targetElement).attach("paste", function(event) {
+ var clipboardData = event.clipboardData;
+ if (clipboardData) {
+ qq.each(clipboardData.items, function(idx, item) {
+ if (isImage(item)) {
+ var blob = item.getAsFile();
+ options.callbacks.pasteReceived(blob);
+ }
+ });
+ }
+ });
+ }
+ function unregisterPasteHandler() {
+ if (detachPasteHandler) {
+ detachPasteHandler();
+ }
+ }
+ qq.extend(options, o);
+ registerPasteHandler();
+ qq.extend(this, {
+ reset: function() {
+ unregisterPasteHandler();
+ }
+ });
+ };
+ qq.FormSupport = function(options, startUpload, log) {
+ "use strict";
+ var self = this, interceptSubmit = options.interceptSubmit, formEl = options.element, autoUpload = options.autoUpload;
+ qq.extend(this, {
+ newEndpoint: null,
+ newAutoUpload: autoUpload,
+ attachedToForm: false,
+ getFormInputsAsObject: function() {
+ if (formEl == null) {
+ return null;
+ }
+ return self._form2Obj(formEl);
+ }
+ });
+ function determineNewEndpoint(formEl) {
+ if (formEl.getAttribute("action")) {
+ self.newEndpoint = formEl.getAttribute("action");
+ }
+ }
+ function validateForm(formEl, nativeSubmit) {
+ if (formEl.checkValidity && !formEl.checkValidity()) {
+ log("Form did not pass validation checks - will not upload.", "error");
+ nativeSubmit();
+ } else {
+ return true;
+ }
+ }
+ function maybeUploadOnSubmit(formEl) {
+ var nativeSubmit = formEl.submit;
+ qq(formEl).attach("submit", function(event) {
+ event = event || window.event;
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
+ validateForm(formEl, nativeSubmit) && startUpload();
+ });
+ formEl.submit = function() {
+ validateForm(formEl, nativeSubmit) && startUpload();
+ };
+ }
+ function determineFormEl(formEl) {
+ if (formEl) {
+ if (qq.isString(formEl)) {
+ formEl = document.getElementById(formEl);
+ }
+ if (formEl) {
+ log("Attaching to form element.");
+ determineNewEndpoint(formEl);
+ interceptSubmit && maybeUploadOnSubmit(formEl);
+ }
+ }
+ return formEl;
+ }
+ formEl = determineFormEl(formEl);
+ this.attachedToForm = !!formEl;
+ };
+ qq.extend(qq.FormSupport.prototype, {
+ _form2Obj: function(form) {
+ "use strict";
+ var obj = {}, notIrrelevantType = function(type) {
+ var irrelevantTypes = [ "button", "image", "reset", "submit" ];
+ return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;
+ }, radioOrCheckbox = function(type) {
+ return qq.indexOf([ "checkbox", "radio" ], type.toLowerCase()) >= 0;
+ }, ignoreValue = function(el) {
+ if (radioOrCheckbox(el.type) && !el.checked) {
+ return true;
+ }
+ return el.disabled && el.type.toLowerCase() !== "hidden";
+ }, selectValue = function(select) {
+ var value = null;
+ qq.each(qq(select).children(), function(idx, child) {
+ if (child.tagName.toLowerCase() === "option" && child.selected) {
+ value = child.value;
+ return false;
+ }
+ });
+ return value;
+ };
+ qq.each(form.elements, function(idx, el) {
+ if ((qq.isInput(el, true) || el.tagName.toLowerCase() === "textarea") && notIrrelevantType(el.type) && !ignoreValue(el)) {
+ obj[el.name] = el.value;
+ } else if (el.tagName.toLowerCase() === "select" && !ignoreValue(el)) {
+ var value = selectValue(el);
+ if (value !== null) {
+ obj[el.name] = value;
+ }
+ }
+ });
+ return obj;
+ }
+ });
+ qq.azure = qq.azure || {};
+ qq.azure.util = qq.azure.util || function() {
+ "use strict";
+ return {
+ AZURE_PARAM_PREFIX: "x-ms-meta-",
+ _paramNameMatchesAzureParameter: function(name) {
+ switch (name) {
+ case "Cache-Control":
+ case "Content-Disposition":
+ case "Content-Encoding":
+ case "Content-MD5":
+ case "x-ms-blob-content-encoding":
+ case "x-ms-blob-content-disposition":
+ case "x-ms-blob-content-md5":
+ case "x-ms-blob-cache-control":
+ return true;
+
+ default:
+ return false;
+ }
+ },
+ _getPrefixedParamName: function(name) {
+ if (qq.azure.util._paramNameMatchesAzureParameter(name)) {
+ return name;
+ } else {
+ return qq.azure.util.AZURE_PARAM_PREFIX + name;
+ }
+ },
+ getParamsAsHeaders: function(params) {
+ var headers = {};
+ qq.each(params, function(name, val) {
+ var headerName = qq.azure.util._getPrefixedParamName(name), value = null;
+ if (qq.isFunction(val)) {
+ value = String(val());
+ } else if (qq.isObject(val)) {
+ qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));
+ } else {
+ value = String(val);
+ }
+ if (value !== null) {
+ if (qq.azure.util._paramNameMatchesAzureParameter(name)) {
+ headers[headerName] = value;
+ } else {
+ headers[headerName] = encodeURIComponent(value);
+ }
+ }
+ });
+ return headers;
+ },
+ parseAzureError: function(responseText, log) {
+ var domParser = new DOMParser(), responseDoc = domParser.parseFromString(responseText, "application/xml"), errorTag = responseDoc.getElementsByTagName("Error")[0], errorDetails = {}, codeTag, messageTag;
+ log("Received error response: " + responseText, "error");
+ if (errorTag) {
+ messageTag = errorTag.getElementsByTagName("Message")[0];
+ if (messageTag) {
+ errorDetails.message = messageTag.textContent;
+ }
+ codeTag = errorTag.getElementsByTagName("Code")[0];
+ if (codeTag) {
+ errorDetails.code = codeTag.textContent;
+ }
+ log("Parsed Azure error: " + JSON.stringify(errorDetails), "error");
+ return errorDetails;
+ }
+ }
+ };
+ }();
+ (function() {
+ "use strict";
+ qq.nonTraditionalBasePublicApi = {
+ setUploadSuccessParams: function(params, id) {
+ this._uploadSuccessParamsStore.set(params, id);
+ },
+ setUploadSuccessEndpoint: function(endpoint, id) {
+ this._uploadSuccessEndpointStore.set(endpoint, id);
+ }
+ };
+ qq.nonTraditionalBasePrivateApi = {
+ _onComplete: function(id, name, result, xhr) {
+ var success = result.success ? true : false, self = this, onCompleteArgs = arguments, successEndpoint = this._uploadSuccessEndpointStore.get(id), successCustomHeaders = this._options.uploadSuccess.customHeaders, successMethod = this._options.uploadSuccess.method, cors = this._options.cors, promise = new qq.Promise(), uploadSuccessParams = this._uploadSuccessParamsStore.get(id), fileParams = this._paramsStore.get(id), onSuccessFromServer = function(successRequestResult) {
+ delete self._failedSuccessRequestCallbacks[id];
+ qq.extend(result, successRequestResult);
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.success(successRequestResult);
+ }, onFailureFromServer = function(successRequestResult) {
+ var callback = submitSuccessRequest;
+ qq.extend(result, successRequestResult);
+ if (result && result.reset) {
+ callback = null;
+ }
+ if (!callback) {
+ delete self._failedSuccessRequestCallbacks[id];
+ } else {
+ self._failedSuccessRequestCallbacks[id] = callback;
+ }
+ if (!self._onAutoRetry(id, name, result, xhr, callback)) {
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.failure(successRequestResult);
+ }
+ }, submitSuccessRequest, successAjaxRequester;
+ if (success && successEndpoint) {
+ successAjaxRequester = new qq.UploadSuccessAjaxRequester({
+ endpoint: successEndpoint,
+ method: successMethod,
+ customHeaders: successCustomHeaders,
+ cors: cors,
+ log: qq.bind(this.log, this)
+ });
+ qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);
+ fileParams && qq.extend(uploadSuccessParams, fileParams, true);
+ submitSuccessRequest = qq.bind(function() {
+ successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams).then(onSuccessFromServer, onFailureFromServer);
+ }, self);
+ submitSuccessRequest();
+ return promise;
+ }
+ return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);
+ },
+ _manualRetry: function(id) {
+ var successRequestCallback = this._failedSuccessRequestCallbacks[id];
+ return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.azure.FineUploaderBasic = function(o) {
+ if (!qq.supportedFeatures.ajaxUploading) {
+ throw new qq.Error("Uploading directly to Azure is not possible in this browser.");
+ }
+ var options = {
+ signature: {
+ endpoint: null,
+ customHeaders: {}
+ },
+ blobProperties: {
+ name: "uuid"
+ },
+ uploadSuccess: {
+ endpoint: null,
+ method: "POST",
+ params: {},
+ customHeaders: {}
+ },
+ chunking: {
+ partSize: 4e6,
+ minFileSize: 4000001
+ }
+ };
+ qq.extend(options, o, true);
+ qq.FineUploaderBasic.call(this, options);
+ this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);
+ this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);
+ this._failedSuccessRequestCallbacks = {};
+ this._cannedBlobNames = {};
+ };
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, {
+ getBlobName: function(id) {
+ if (this._cannedBlobNames[id] == null) {
+ return this._handler.getThirdPartyFileId(id);
+ }
+ return this._cannedBlobNames[id];
+ },
+ _getEndpointSpecificParams: function(id) {
+ return {
+ blob: this.getBlobName(id),
+ uuid: this.getUuid(id),
+ name: this.getName(id),
+ container: this._endpointStore.get(id)
+ };
+ },
+ _createUploadHandler: function() {
+ return qq.FineUploaderBasic.prototype._createUploadHandler.call(this, {
+ signature: this._options.signature,
+ onGetBlobName: qq.bind(this._determineBlobName, this),
+ deleteBlob: qq.bind(this._deleteBlob, this, true)
+ }, "azure");
+ },
+ _determineBlobName: function(id) {
+ var self = this, blobNameOptionValue = this._options.blobProperties.name, uuid = this.getUuid(id), filename = this.getName(id), fileExtension = qq.getExtension(filename), blobNameToUse = uuid;
+ if (qq.isString(blobNameOptionValue)) {
+ switch (blobNameOptionValue) {
+ case "uuid":
+ if (fileExtension !== undefined) {
+ blobNameToUse += "." + fileExtension;
+ }
+ return new qq.Promise().success(blobNameToUse);
+
+ case "filename":
+ return new qq.Promise().success(filename);
+
+ default:
+ return new qq.Promise.failure("Invalid blobName option value - " + blobNameOptionValue);
+ }
+ } else {
+ return blobNameOptionValue.call(this, id);
+ }
+ },
+ _addCannedFile: function(sessionData) {
+ var id;
+ if (sessionData.blobName == null) {
+ throw new qq.Error("Did not find blob name property in server session response. This is required!");
+ } else {
+ id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);
+ this._cannedBlobNames[id] = sessionData.blobName;
+ }
+ return id;
+ },
+ _deleteBlob: function(relatedToCancel, id) {
+ var self = this, deleteBlobSasUri = {}, blobUriStore = {
+ get: function(id) {
+ return self._endpointStore.get(id) + "/" + self.getBlobName(id);
+ }
+ }, deleteFileEndpointStore = {
+ get: function(id) {
+ return deleteBlobSasUri[id];
+ }
+ }, getSasSuccess = function(id, sasUri) {
+ deleteBlobSasUri[id] = sasUri;
+ deleteBlob.send(id);
+ }, getSasFailure = function(id, reason, xhr) {
+ if (relatedToCancel) {
+ self.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS", "error");
+ qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));
+ } else {
+ self._onDeleteComplete(id, xhr, true);
+ self._options.callbacks.onDeleteComplete(id, xhr, true);
+ }
+ }, deleteBlob = new qq.azure.DeleteBlob({
+ endpointStore: deleteFileEndpointStore,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ delete deleteBlobSasUri[id];
+ if (isError) {
+ if (relatedToCancel) {
+ self.log("Will cancel upload, but failed to remove uncommitted parts from Azure.", "error");
+ } else {
+ qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));
+ }
+ }
+ if (relatedToCancel) {
+ qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));
+ self.log("Deleted uncommitted blob chunks for " + id);
+ } else {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ }
+ }), getSas = new qq.azure.GetSas({
+ cors: this._options.cors,
+ customHeaders: this._options.signature.customHeaders,
+ endpointStore: {
+ get: function() {
+ return self._options.signature.endpoint;
+ }
+ },
+ restRequestVerb: deleteBlob.method,
+ log: qq.bind(self.log, self)
+ });
+ getSas.request(id, blobUriStore.get(id)).then(qq.bind(getSasSuccess, self, id), qq.bind(getSasFailure, self, id));
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return {
+ sendDelete: function(id, uuid) {
+ self._deleteBlob(false, id);
+ }
+ };
+ }
+ });
+ })();
+ qq.azure.XhrUploadHandler = function(spec, proxy) {
+ "use strict";
+ var handler = this, log = proxy.log, cors = spec.cors, endpointStore = spec.endpointStore, paramsStore = spec.paramsStore, signature = spec.signature, filenameParam = spec.filenameParam, minFileSizeForChunking = spec.chunking.minFileSize, deleteBlob = spec.deleteBlob, onGetBlobName = spec.onGetBlobName, getName = proxy.getName, getSize = proxy.getSize, getBlobMetadata = function(id) {
+ var params = paramsStore.get(id);
+ params[filenameParam] = getName(id);
+ return params;
+ }, api = {
+ putBlob: new qq.azure.PutBlob({
+ getBlobMetadata: getBlobMetadata,
+ log: log
+ }),
+ putBlock: new qq.azure.PutBlock({
+ log: log
+ }),
+ putBlockList: new qq.azure.PutBlockList({
+ getBlobMetadata: getBlobMetadata,
+ log: log
+ }),
+ getSasForPutBlobOrBlock: new qq.azure.GetSas({
+ cors: cors,
+ customHeaders: signature.customHeaders,
+ endpointStore: {
+ get: function() {
+ return signature.endpoint;
+ }
+ },
+ log: log,
+ restRequestVerb: "PUT"
+ })
+ };
+ function combineChunks(id) {
+ var promise = new qq.Promise();
+ getSignedUrl(id).then(function(sasUri) {
+ var mimeType = handler._getMimeType(id), blockIdEntries = handler._getPersistableData(id).blockIdEntries;
+ api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {
+ handler._registerXhr(id, null, xhr, api.putBlockList);
+ }).then(function(xhr) {
+ log("Success combining chunks for id " + id);
+ promise.success({}, xhr);
+ }, function(xhr) {
+ log("Attempt to combine chunks failed for id " + id, "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ }
+ function determineBlobUrl(id) {
+ var containerUrl = endpointStore.get(id), promise = new qq.Promise(), getBlobNameSuccess = function(blobName) {
+ handler._setThirdPartyFileId(id, blobName);
+ promise.success(containerUrl + "/" + blobName);
+ }, getBlobNameFailure = function(reason) {
+ promise.failure(reason);
+ };
+ onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);
+ return promise;
+ }
+ function getSignedUrl(id, optChunkIdx) {
+ var getSasId = optChunkIdx == null ? id : id + "." + optChunkIdx, promise = new qq.Promise(), getSasSuccess = function(sasUri) {
+ log("GET SAS request succeeded.");
+ promise.success(sasUri);
+ }, getSasFailure = function(reason, getSasXhr) {
+ log("GET SAS request failed: " + reason, "error");
+ promise.failure({
+ error: "Problem communicating with local server"
+ }, getSasXhr);
+ }, determineBlobUrlSuccess = function(blobUrl) {
+ api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(getSasSuccess, getSasFailure);
+ }, determineBlobUrlFailure = function(reason) {
+ log(qq.format("Failed to determine blob name for ID {} - {}", id, reason), "error");
+ promise.failure({
+ error: reason
+ });
+ };
+ determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);
+ return promise;
+ }
+ function handleFailure(xhr, promise) {
+ var azureError = qq.azure.util.parseAzureError(xhr.responseText, log), errorMsg = "Problem sending file to Azure";
+ promise.failure({
+ error: errorMsg,
+ azureError: azureError && azureError.message,
+ reset: xhr.status === 403
+ });
+ }
+ qq.extend(this, {
+ uploadChunk: function(id, chunkIdx) {
+ var promise = new qq.Promise();
+ getSignedUrl(id, chunkIdx).then(function(sasUri) {
+ var xhr = handler._createXhr(id, chunkIdx), chunkData = handler._getChunkData(id, chunkIdx);
+ handler._registerProgressHandler(id, chunkIdx, chunkData.size);
+ handler._registerXhr(id, chunkIdx, xhr, api.putBlock);
+ api.putBlock.upload(id + "." + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(function(blockIdEntry) {
+ if (!handler._getPersistableData(id).blockIdEntries) {
+ handler._getPersistableData(id).blockIdEntries = [];
+ }
+ handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);
+ log("Put Block call succeeded for " + id);
+ promise.success({}, xhr);
+ }, function() {
+ log(qq.format("Put Block call failed for ID {} on part {}", id, chunkIdx), "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ },
+ uploadFile: function(id) {
+ var promise = new qq.Promise(), fileOrBlob = handler.getFile(id);
+ getSignedUrl(id).then(function(sasUri) {
+ var xhr = handler._createXhr(id);
+ handler._registerProgressHandler(id);
+ api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(function() {
+ log("Put Blob call succeeded for " + id);
+ promise.success({}, xhr);
+ }, function() {
+ log("Put Blob call failed for " + id, "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ }
+ });
+ qq.extend(this, new qq.XhrUploadHandler({
+ options: qq.extend({
+ namespace: "azure"
+ }, spec),
+ proxy: qq.extend({
+ getEndpoint: spec.endpointStore.get
+ }, proxy)
+ }));
+ qq.override(this, function(super_) {
+ return {
+ expunge: function(id) {
+ var relatedToCancel = handler._wasCanceled(id), chunkingData = handler._getPersistableData(id), blockIdEntries = chunkingData && chunkingData.blockIdEntries || [];
+ if (relatedToCancel && blockIdEntries.length > 0) {
+ deleteBlob(id);
+ }
+ super_.expunge(id);
+ },
+ finalizeChunks: function(id) {
+ return combineChunks(id);
+ },
+ _shouldChunkThisFile: function(id) {
+ var maybePossible = super_._shouldChunkThisFile(id);
+ return maybePossible && getSize(id) >= minFileSizeForChunking;
+ }
+ };
+ });
+ };
+ qq.azure.GetSas = function(o) {
+ "use strict";
+ var requester, options = {
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ customHeaders: {},
+ restRequestVerb: "PUT",
+ endpointStore: null,
+ log: function(str, level) {}
+ }, requestPromises = {};
+ qq.extend(options, o);
+ function sasResponseReceived(id, xhr, isError) {
+ var promise = requestPromises[id];
+ if (isError) {
+ promise.failure("Received response code " + xhr.status, xhr);
+ } else {
+ if (xhr.responseText.length) {
+ promise.success(xhr.responseText);
+ } else {
+ promise.failure("Empty response.", xhr);
+ }
+ }
+ delete requestPromises[id];
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ successfulResponseCodes: {
+ GET: [ 200 ]
+ },
+ contentType: null,
+ customHeaders: options.customHeaders,
+ endpointStore: options.endpointStore,
+ cors: options.cors,
+ log: options.log,
+ onComplete: sasResponseReceived
+ }));
+ qq.extend(this, {
+ request: function(id, blobUri) {
+ var requestPromise = new qq.Promise(), restVerb = options.restRequestVerb;
+ options.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.", restVerb, id));
+ requestPromises[id] = requestPromise;
+ requester.initTransport(id).withParams({
+ bloburi: blobUri,
+ _method: restVerb
+ }).withCacheBuster().send();
+ return requestPromise;
+ }
+ });
+ };
+ qq.UploadSuccessAjaxRequester = function(o) {
+ "use strict";
+ var requester, pendingRequests = [], options = {
+ method: "POST",
+ endpoint: null,
+ maxConnections: 3,
+ customHeaders: {},
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {}
+ };
+ qq.extend(options, o);
+ function handleSuccessResponse(id, xhrOrXdr, isError) {
+ var promise = pendingRequests[id], responseJson = xhrOrXdr.responseText, successIndicator = {
+ success: true
+ }, failureIndicator = {
+ success: false
+ }, parsedResponse;
+ delete pendingRequests[id];
+ options.log(qq.format("Received the following response body to an upload success request for id {}: {}", id, responseJson));
+ try {
+ parsedResponse = qq.parseJson(responseJson);
+ if (isError || parsedResponse && (parsedResponse.error || parsedResponse.success === false)) {
+ options.log("Upload success request was rejected by the server.", "error");
+ promise.failure(qq.extend(parsedResponse, failureIndicator));
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(qq.extend(parsedResponse, successIndicator));
+ }
+ } catch (error) {
+ if (isError) {
+ options.log(qq.format("Your server indicated failure in its upload success request response for id {}!", id), "error");
+ promise.failure(failureIndicator);
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(successIndicator);
+ }
+ }
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ method: options.method,
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ paramsStore: options.paramsStore,
+ maxConnections: options.maxConnections,
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: handleSuccessResponse,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendSuccessRequest: function(id, spec) {
+ var promise = new qq.Promise();
+ options.log("Submitting upload success request/notification for " + id);
+ requester.initTransport(id).withParams(spec).send();
+ pendingRequests[id] = promise;
+ return promise;
+ }
+ });
+ };
+ qq.azure.DeleteBlob = function(o) {
+ "use strict";
+ var requester, method = "DELETE", options = {
+ endpointStore: {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhr, isError) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 202 ];
+ return codes;
+ }(),
+ contentType: null,
+ endpointStore: options.endpointStore,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete
+ }));
+ qq.extend(this, {
+ method: method,
+ send: function(id) {
+ options.log("Submitting Delete Blob request for " + id);
+ return requester.initTransport(id).send();
+ }
+ });
+ };
+ qq.azure.PutBlob = function(o) {
+ "use strict";
+ var requester, method = "PUT", options = {
+ getBlobMetadata: function(id) {},
+ log: function(str, level) {}
+ }, endpoints = {}, promises = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ contentType: null,
+ customHeaders: function(id) {
+ var params = options.getBlobMetadata(id), headers = qq.azure.util.getParamsAsHeaders(params);
+ headers["x-ms-blob-type"] = "BlockBlob";
+ return headers;
+ },
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id];
+ delete endpoints[id];
+ delete promises[id];
+ if (isError) {
+ promise.failure();
+ } else {
+ promise.success();
+ }
+ }
+ }));
+ qq.extend(this, {
+ method: method,
+ upload: function(id, xhr, url, file) {
+ var promise = new qq.Promise();
+ options.log("Submitting Put Blob request for " + id);
+ promises[id] = promise;
+ endpoints[id] = url;
+ requester.initTransport(id).withPayload(file).withHeaders({
+ "Content-Type": file.type
+ }).send(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.azure.PutBlock = function(o) {
+ "use strict";
+ var requester, method = "PUT", blockIdEntries = {}, promises = {}, options = {
+ log: function(str, level) {}
+ }, endpoints = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ contentType: null,
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id], blockIdEntry = blockIdEntries[id];
+ delete endpoints[id];
+ delete promises[id];
+ delete blockIdEntries[id];
+ if (isError) {
+ promise.failure();
+ } else {
+ promise.success(blockIdEntry);
+ }
+ }
+ }));
+ function createBlockId(partNum) {
+ var digits = 5, zeros = new Array(digits + 1).join("0"), paddedPartNum = (zeros + partNum).slice(-digits);
+ return btoa(paddedPartNum);
+ }
+ qq.extend(this, {
+ method: method,
+ upload: function(id, xhr, sasUri, partNum, blob) {
+ var promise = new qq.Promise(), blockId = createBlockId(partNum);
+ promises[id] = promise;
+ options.log(qq.format("Submitting Put Block request for {} = part {}", id, partNum));
+ endpoints[id] = qq.format("{}&comp=block&blockid={}", sasUri, encodeURIComponent(blockId));
+ blockIdEntries[id] = {
+ part: partNum,
+ id: blockId
+ };
+ requester.initTransport(id).withPayload(blob).send(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.azure.PutBlockList = function(o) {
+ "use strict";
+ var requester, method = "PUT", promises = {}, options = {
+ getBlobMetadata: function(id) {},
+ log: function(str, level) {}
+ }, endpoints = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ customHeaders: function(id) {
+ var params = options.getBlobMetadata(id);
+ return qq.azure.util.getParamsAsHeaders(params);
+ },
+ contentType: "text/plain",
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onSend: function() {},
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id];
+ delete endpoints[id];
+ delete promises[id];
+ if (isError) {
+ promise.failure(xhr);
+ } else {
+ promise.success(xhr);
+ }
+ }
+ }));
+ function createRequestBody(blockIdEntries) {
+ var doc = document.implementation.createDocument(null, "BlockList", null);
+ blockIdEntries.sort(function(a, b) {
+ return a.part - b.part;
+ });
+ qq.each(blockIdEntries, function(idx, blockIdEntry) {
+ var latestEl = doc.createElement("Latest"), latestTextEl = doc.createTextNode(blockIdEntry.id);
+ latestEl.appendChild(latestTextEl);
+ qq(doc).children()[0].appendChild(latestEl);
+ });
+ return new XMLSerializer().serializeToString(doc);
+ }
+ qq.extend(this, {
+ method: method,
+ send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {
+ var promise = new qq.Promise(), blockIdsXml = createRequestBody(blockIdEntries), xhr;
+ promises[id] = promise;
+ options.log(qq.format("Submitting Put Block List request for {}", id));
+ endpoints[id] = qq.format("{}&comp=blocklist", sasUri);
+ xhr = requester.initTransport(id).withPayload(blockIdsXml).withHeaders({
+ "x-ms-blob-content-type": fileMimeType
+ }).send();
+ registerXhrCallback(xhr);
+ return promise;
+ }
+ });
+ };
+})(window);
+//# sourceMappingURL=azure.fine-uploader.core.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.js.map b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.js.map
new file mode 100644
index 000000000000..2d6273b2bfe6
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/azure/util.js","../client/js/non-traditional-common/uploader.basic.api.js","../client/js/azure/uploader.basic.js","../client/js/azure/azure.xhr.upload.handler.js","../client/js/azure/get-sas.js","../client/js/uploadsuccess.ajax.requester.js","../client/js/azure/rest/delete-blob.js","../client/js/azure/rest/put-blob.js","../client/js/azure/rest/put-block.js","../client/js/azure/rest/put-block-list.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","intArray","mimeString","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","testSupportsFileInputElement","supported","tempInput","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","self","disposeSupport","options","acceptFiles","focusClass","folders","hoverClass","ios8BrowserCrashWorkaround","onChange","title","buttonId","createInput","BUTTON_ID_ATTR_NAME","setMultiple","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","byUuid","byStatus","byProxyGroupId","byBatchId","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","getDataByStatus","status","statusResults","statuses","index","statusEnum","statusResultIndexes","dataIndex","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","params","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","_options","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","promiseToReturn","fileOrUrl","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","callbacks","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","toUpperCase","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","accept","validation","allowedExtensions","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","namespace","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","messages","names","validationBase","extensionsForMessage","placeholderMatch","replacement","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","shouldParamsBeInQueryString","queue","requestData","acceptHeader","validMethods","contentType","mandatedParams","allowXRequestedWithAndCacheControl","successfulResponseCodes","DELETE","PATCH","POST","PUT","GET","onSend","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","dequeue","nextId","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","optXhr","payload","url","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","setRequestHeader","responseCode","prepareToSend","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","controller","chunkingPossible","concurrentChunkingPossible","preventRetryResponse","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","responseToReport","inProgressIdx","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","formHandlerInstanceId","onloadCallbacks","detachLoadEvents","postMessageCallbackTimers","isCors","corsMessageReceiver","expungeFile","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","_parseJsonResponse","onloadCallback","_detachLoadEvent","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","chunkFiles","resumeEnabled","xhrId","ajaxRequester","_getAjaxRequester","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","requester","getMandatedParams","_method","detectSubsampling","img","iw","naturalWidth","ih","naturalHeight","ctx","width","getContext","drawImage","getImageData","detectVerticalSquash","sy","ey","py","alpha","ratio","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","d","tmpCanvas","vertSquashRatio","dw","dh","dy","tmpCtx","sx","dx","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","imgWidth","imgHeight","opt","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","el","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetAnchor","targetProtocol","targetHostname","targetPort","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","rendered","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","TAG_IDS","TAG_INFO","274","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","vals","idHex","tagsToFindIdx","tagValHex","tagValLength","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","output","chr1","chr2","chr3","enc1","enc2","enc3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","detachPasteHandler","isImage","registerPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","formEl","_form2Obj","determineNewEndpoint","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","azure","util","AZURE_PARAM_PREFIX","_paramNameMatchesAzureParameter","_getPrefixedParamName","getParamsAsHeaders","headerName","parseAzureError","domParser","DOMParser","responseDoc","parseFromString","errorTag","errorDetails","codeTag","messageTag","nonTraditionalBasePublicApi","setUploadSuccessParams","_uploadSuccessParamsStore","setUploadSuccessEndpoint","_uploadSuccessEndpointStore","nonTraditionalBasePrivateApi","onCompleteArgs","successEndpoint","successCustomHeaders","uploadSuccess","successMethod","uploadSuccessParams","fileParams","onSuccessFromServer","successRequestResult","_failedSuccessRequestCallbacks","onFailureFromServer","submitSuccessRequest","successAjaxRequester","UploadSuccessAjaxRequester","_getEndpointSpecificParams","sendSuccessRequest","successRequestCallback","signature","blobProperties","minFileSize","_cannedBlobNames","getBlobName","onGetBlobName","_determineBlobName","deleteBlob","_deleteBlob","blobNameOptionValue","fileExtension","blobNameToUse","blobName","relatedToCancel","deleteBlobSasUri","blobUriStore","deleteFileEndpointStore","getSasSuccess","sasUri","getSasFailure","DeleteBlob","getSas","GetSas","restRequestVerb","minFileSizeForChunking","getBlobMetadata","putBlob","PutBlob","putBlock","PutBlock","putBlockList","PutBlockList","getSasForPutBlobOrBlock","combineChunks","getSignedUrl","mimeType","blockIdEntries","determineBlobUrl","containerUrl","getBlobNameSuccess","getBlobNameFailure","getSasId","getSasXhr","determineBlobUrlSuccess","blobUrl","determineBlobUrlFailure","azureError","blockIdEntry","chunkingData","maybePossible","requestPromises","sasResponseReceived","blobUri","requestPromise","restVerb","bloburi","pendingRequests","handleSuccessResponse","responseJson","successIndicator","failureIndicator","parsedResponse","codes","endpoints","promises","endpointHandler","Content-Type","createBlockId","partNum","digits","zeros","paddedPartNum","btoa","blockId","createRequestBody","doc","implementation","createDocument","latestEl","latestTextEl","createTextNode","XMLSerializer","serializeToString","fileMimeType","registerXhrCallback","blockIdsXml","x-ms-blob-content-type"],"mappings":"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","file":"azure.fine-uploader.core.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\"\"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.min.js b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.min.js
new file mode 100644
index 000000000000..1cf22bbe5551
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.min.js
@@ -0,0 +1,6 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+!function(global,global){var qq=function(e){"use strict";return{hide:function(){return e.style.display="none",this},attach:function(t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n),function(){qq(e).detach(t,n)}},detach:function(t,n){return e.removeEventListener?e.removeEventListener(t,n,!1):e.attachEvent&&e.detachEvent("on"+t,n),this},contains:function(t){return!!t&&(e===t||(e.contains?e.contains(t):!!(8&t.compareDocumentPosition(e))))},insertBefore:function(t){return t.parentNode.insertBefore(e,t),this},remove:function(){return e.parentNode.removeChild(e),this},css:function(t){if(null==e.style)throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");return null!=t.opacity&&"string"!=typeof e.style.opacity&&"undefined"!=typeof e.filters&&(t.filter="alpha(opacity="+Math.round(100*t.opacity)+")"),qq.extend(e.style,t),this},hasClass:function(t,n){var i=new RegExp("(^| )"+t+"( |$)");return i.test(e.className)||!(!n||!i.test(e.parentNode.className))},addClass:function(t){return qq(e).hasClass(t)||(e.className+=" "+t),this},removeClass:function(t){var n=new RegExp("(^| )"+t+"( |$)");return e.className=e.className.replace(n," ").replace(/^\s+|\s+$/g,""),this},getByClass:function(t,n){var i,o=[];return n&&e.querySelector?e.querySelector("."+t):e.querySelectorAll?e.querySelectorAll("."+t):(i=e.getElementsByTagName("*"),qq.each(i,function(e,n){qq(n).hasClass(t)&&o.push(n)}),n?o[0]:o)},getFirstByClass:function(t){return qq(e).getByClass(t,!0)},children:function(){for(var t=[],n=e.firstChild;n;)1===n.nodeType&&t.push(n),n=n.nextSibling;return t},setText:function(t){return e.innerText=t,e.textContent=t,this},clearText:function(){return qq(e).setText("")},hasAttribute:function(t){var n;return e.hasAttribute?!!e.hasAttribute(t)&&null==/^false$/i.exec(e.getAttribute(t)):(n=e[t],void 0!==n&&null==/^false$/i.exec(n))}}};!function(){"use strict";qq.canvasToBlob=function(e,t,n){return qq.dataUriToBlob(e.toDataURL(t,n))},qq.dataUriToBlob=function(e){var t,n,i,o,r=function(e,t){var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})};return n=e.split(",")[0].indexOf("base64")>=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),o=e.split(",")[0].split(":")[1].split(";")[0],t=new ArrayBuffer(n.length),i=new Uint8Array(t),qq.each(n,function(e,t){i[e]=t.charCodeAt(0)}),r(t,o)},qq.log=function(e,t){window.console&&(t&&"info"!==t?window.console[t]?window.console[t](e):window.console.log("<"+t+"> "+e):window.console.log(e))},qq.isObject=function(e){return e&&!e.nodeType&&"[object Object]"===Object.prototype.toString.call(e)},qq.isFunction=function(e){return"function"==typeof e},qq.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)||e&&window.ArrayBuffer&&e.buffer&&e.buffer.constructor===ArrayBuffer},qq.isItemList=function(e){return"[object DataTransferItemList]"===Object.prototype.toString.call(e)},qq.isNodeList=function(e){return"[object NodeList]"===Object.prototype.toString.call(e)||e.item&&e.namedItem},qq.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},qq.trimStr=function(e){return String.prototype.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},qq.format=function(e){var t=Array.prototype.slice.call(arguments,1),n=e,i=n.indexOf("{}");return qq.each(t,function(e,t){var o=n.substring(0,i),r=n.substring(i+2);if(n=o+t+r,i=n.indexOf("{}",i+t.length),i<0)return!1}),n},qq.isFile=function(e){return window.File&&"[object File]"===Object.prototype.toString.call(e)},qq.isFileList=function(e){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(e)},qq.isFileOrInput=function(e){return qq.isFile(e)||qq.isInput(e)},qq.isInput=function(e,t){var n=function(e){var n=e.toLowerCase();return t?"file"!==n:"file"===n};return!!(window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(e)&&e.type&&n(e.type))||!!(e.tagName&&"input"===e.tagName.toLowerCase()&&e.type&&n(e.type))},qq.isBlob=function(e){if(window.Blob&&"[object Blob]"===Object.prototype.toString.call(e))return!0},qq.isXhrUploadSupported=function(){var e=document.createElement("input");return e.type="file",void 0!==e.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&"undefined"!=typeof qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(e){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(e){return e.items&&e.items.length>0&&e.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(e,t,n){var i=e.slice||e.mozSlice||e.webkitSlice;return i.call(e,t,n)},qq.arrayBufferToHex=function(e){var t="",n=new Uint8Array(e);return qq.each(n,function(e,n){var i=n.toString(16);i.length<2&&(i="0"+i),t+=i}),t},qq.readBlobToHex=function(e,t,n){var i=qq.sliceBlob(e,t,t+n),o=new FileReader,r=new qq.Promise;return o.onload=function(){r.success(qq.arrayBufferToHex(o.result))},o.onerror=r.failure,o.readAsArrayBuffer(i),r},qq.extend=function(e,t,n){return qq.each(t,function(t,i){n&&qq.isObject(i)?(void 0===e[t]&&(e[t]={}),qq.extend(e[t],i,!0)):e[t]=i}),e},qq.override=function(e,t){var n={},i=t(n);return qq.each(i,function(t,i){void 0!==e[t]&&(n[t]=e[t]),e[t]=i}),e},qq.indexOf=function(e,t,n){if(e.indexOf)return e.indexOf(t,n);n=n||0;var i=e.length;for(n<0&&(n+=i);n=0},qq.safari=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Apple")!==-1},qq.chrome=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Google")!==-1},qq.opera=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Opera")!==-1},qq.firefox=function(){return!qq.edge()&&!qq.ie11()&&navigator.userAgent.indexOf("Mozilla")!==-1&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return navigator.userAgent.toLowerCase().indexOf("android")!==-1},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 6_")!==-1},qq.ios7=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 7_")!==-1},qq.ios8=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_")!==-1},qq.ios800=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_0 ")!==-1},qq.ios=function(){return navigator.userAgent.indexOf("iPad")!==-1||navigator.userAgent.indexOf("iPod")!==-1||navigator.userAgent.indexOf("iPhone")!==-1},qq.iosChrome=function(){return qq.ios()&&navigator.userAgent.indexOf("CriOS")!==-1},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&navigator.userAgent.indexOf("Safari")!==-1},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},qq.toElement=function(){var e=document.createElement("div");return function(t){e.innerHTML=t;var n=e.firstChild;return e.removeChild(n),n}}(),qq.each=function(e,t){var n,i;if(e)if(window.Storage&&e.constructor===window.Storage)for(n=0;n0)return e.substr(t,e.length-t)},qq.getFilename=function(e){return qq.isInput(e)?e.value.replace(/.*(\/|\\)/,""):qq.isFile(e)&&null!==e.fileName&&void 0!==e.fileName?e.fileName:e.name},qq.DisposeSupport=function(){var e=[];return{dispose:function(){var t;do t=e.shift(),t&&t();while(t)},attach:function(){var e=arguments;this.addDisposer(qq(e[0]).attach.apply(this,Array.prototype.slice.call(arguments,1)))},addDisposer:function(t){e.push(t)}}}}(),function(){"use strict";"function"==typeof define&&define.amd?define(function(){return qq}):"undefined"!=typeof module&&module.exports?module.exports=qq:global.qq=qq}(),function(){"use strict";qq.Error=function(e){this.message="[Fine Uploader "+qq.version+"] "+e},qq.Error.prototype=new Error}(),qq.version="5.13.0",qq.supportedFeatures=function(){"use strict";function e(){var e,t=!0;try{e=document.createElement("input"),e.type="file",qq(e).hide(),e.disabled&&(t=!1)}catch(e){t=!1}return t}function t(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/)}function n(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/)}function i(){if(window.XMLHttpRequest){var e=qq.createXhrInstance();return void 0!==e.withCredentials}return!1}function o(){return void 0!==window.XDomainRequest}function r(){return!!i()||o()}function a(){return void 0!==document.createElement("input").webkitdirectory}function s(){try{return!!window.localStorage&&qq.isFunction(window.localStorage.setItem)}catch(e){return!1}}function u(){var e=document.createElement("span");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&!qq.android()&&!qq.ios()}var l,c,d,q,p,f,h,m,g,_,b,v,S,w,x;return l=e(),q=l&&qq.isXhrUploadSupported(),c=q&&!qq.androidStock(),d=q&&u(),p=d&&t(),f=q&&qq.isFileChunkingSupported(),h=q&&f&&s(),m=q&&n(),g=l&&(void 0!==window.postMessage||q),b=i(),_=o(),v=r(),S=a(),w=q&&void 0!==window.FileReader,x=function(){return!!q&&(!qq.androidStock()&&!qq.iosChrome())}(),{ajaxUploading:q,blobUploading:c,canDetermineSize:q,chunking:f,deleteFileCors:v,deleteFileCorsXdr:_,deleteFileCorsXhr:b,dialogElement:!!window.HTMLDialogElement,fileDrop:d,folderDrop:p,folderSelection:S,imagePreviews:w,imageValidation:w,itemSizeValidation:q,pause:f,progressBar:x,resume:h,scaling:w&&c,tiffPreviews:qq.safari(),unlimitedScaledImageSize:!qq.ios(),uploading:l,uploadCors:g,uploadCustomHeaders:q,uploadNonMultipart:q,uploadViaPaste:m}}(),qq.isGenericPromise=function(e){"use strict";return!!(e&&e.then&&qq.isFunction(e.then))},qq.Promise=function(){"use strict";var e,t,n=[],i=[],o=[],r=0;qq.extend(this,{then:function(o,a){return 0===r?(o&&n.push(o),a&&i.push(a)):r===-1?a&&a.apply(null,t):o&&o.apply(null,e),this},done:function(n){return 0===r?o.push(n):n.apply(null,void 0===t?e:t),this},success:function(){return r=1,e=arguments,n.length&&qq.each(n,function(t,n){n.apply(null,e)}),o.length&&qq.each(o,function(t,n){n.apply(null,e)}),this},failure:function(){return r=-1,t=arguments,i.length&&qq.each(i,function(e,n){n.apply(null,t)}),o.length&&qq.each(o,function(e,n){n.apply(null,t)}),this}})},qq.BlobProxy=function(e,t){"use strict";qq.extend(this,{referenceBlob:e,create:function(){return t(e)}})},qq.UploadButton=function(e){"use strict";function t(){var e=document.createElement("input");return e.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME,i),e.setAttribute("title",a.title),o.setMultiple(a.multiple,e),a.folders&&qq.supportedFeatures.folderSelection&&e.setAttribute("webkitdirectory",""),a.acceptFiles&&e.setAttribute("accept",a.acceptFiles),e.setAttribute("type","file"),e.setAttribute("name",a.name),qq(e).css({position:"absolute",right:0,top:0,fontFamily:"Arial",fontSize:qq.ie()&&!qq.ie8()?"3500px":"118px",margin:0,padding:0,cursor:"pointer",opacity:0}),!qq.ie7()&&qq(e).css({height:"100%"}),a.element.appendChild(e),r.attach(e,"change",function(){a.onChange(e)}),r.attach(e,"mouseover",function(){qq(a.element).addClass(a.hoverClass)}),r.attach(e,"mouseout",function(){qq(a.element).removeClass(a.hoverClass)}),r.attach(e,"focus",function(){qq(a.element).addClass(a.focusClass)}),r.attach(e,"blur",function(){qq(a.element).removeClass(a.focusClass)}),e}var n,i,o=this,r=new qq.DisposeSupport,a={acceptFiles:null,element:null,focusClass:"qq-upload-button-focus",folders:!1,hoverClass:"qq-upload-button-hover",ios8BrowserCrashWorkaround:!1,multiple:!1,name:"qqfile",onChange:function(e){},title:null};qq.extend(a,e),i=qq.getUniqueId(),qq(a.element).css({position:"relative",overflow:"hidden",direction:"ltr"}),qq.extend(this,{getInput:function(){return n},getButtonId:function(){return i},setMultiple:function(e,t){var n=t||this.getInput();a.ios8BrowserCrashWorkaround&&qq.ios8()&&(qq.iosChrome()||qq.iosSafariWebView())?n.setAttribute("multiple",""):e?n.setAttribute("multiple",""):n.removeAttribute("multiple")},setAcceptFiles:function(e){e!==a.acceptFiles&&n.setAttribute("accept",e)},reset:function(){n.parentNode&&qq(n).remove(),qq(a.element).removeClass(a.focusClass),n=null,n=t()}}),n=t()},qq.UploadButton.BUTTON_ID_ATTR_NAME="qq-button-id",qq.UploadData=function(e){"use strict";function t(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[n])}),t}return o[e]}function n(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[r[n]])}),t}return o[r[e]]}function i(e){var t=[],n=[].concat(e);return qq.each(n,function(e,n){var i=a[n];void 0!==i&&qq.each(i,function(e,n){t.push(o[n])})}),t}var o=[],r={},a={},s={},u={};qq.extend(this,{addFile:function(t){var n=t.status||qq.status.SUBMITTING,i=o.push({name:t.name,originalName:t.name,uuid:t.uuid,size:null==t.size?-1:t.size,status:n})-1;return t.batchId&&(o[i].batchId=t.batchId,void 0===u[t.batchId]&&(u[t.batchId]=[]),u[t.batchId].push(i)),t.proxyGroupId&&(o[i].proxyGroupId=t.proxyGroupId,void 0===s[t.proxyGroupId]&&(s[t.proxyGroupId]=[]),s[t.proxyGroupId].push(i)),o[i].id=i,r[t.uuid]=i,void 0===a[n]&&(a[n]=[]),a[n].push(i),e.onStatusChange(i,null,n),i},retrieve:function(e){return qq.isObject(e)&&o.length?void 0!==e.id?t(e.id):void 0!==e.uuid?n(e.uuid):e.status?i(e.status):void 0:qq.extend([],o,!0)},reset:function(){o=[],r={},a={},u={}},setStatus:function(t,n){var i=o[t].status,r=qq.indexOf(a[i],t);a[i].splice(r,1),o[t].status=n,void 0===a[n]&&(a[n]=[]),a[n].push(t),e.onStatusChange(t,i,n)},uuidChanged:function(e,t){var n=o[e].uuid;o[e].uuid=t,r[t]=e,delete r[n]},updateName:function(e,t){o[e].name=t},updateSize:function(e,t){o[e].size=t},setParentId:function(e,t){o[e].parentId=t},getIdsInProxyGroup:function(e){var t=o[e].proxyGroupId;return t?s[t]:[]},getIdsInBatch:function(e){var t=o[e].batchId;return u[t]}})},qq.status={SUBMITTING:"submitting",SUBMITTED:"submitted",REJECTED:"rejected",QUEUED:"queued",CANCELED:"canceled",PAUSED:"paused",UPLOADING:"uploading",UPLOAD_RETRYING:"retrying upload",UPLOAD_SUCCESSFUL:"upload successful",UPLOAD_FAILED:"upload failed",DELETE_FAILED:"delete failed",DELETING:"deleting",DELETED:"deleted"},function(){"use strict";qq.basePublicApi={addBlobs:function(e,t,n){this.addFiles(e,t,n)},addInitialFiles:function(e){var t=this;qq.each(e,function(e,n){t._addCannedFile(n)})},addFiles:function(e,t,n){this._maybeHandleIos8SafariWorkaround();var i=0===this._storedIds.length?qq.getUniqueId():this._currentBatchId,o=qq.bind(function(e){this._handleNewFile({blob:e,name:this._options.blobs.defaultName},i,d)},this),r=qq.bind(function(e){this._handleNewFile(e,i,d)},this),a=qq.bind(function(e){var t=qq.canvasToBlob(e);this._handleNewFile({blob:t,name:this._options.blobs.defaultName+".png"},i,d)},this),s=qq.bind(function(e){var t=e.quality&&e.quality/100,n=qq.canvasToBlob(e.canvas,e.type,t);this._handleNewFile({blob:n,name:e.name},i,d)},this),u=qq.bind(function(e){if(qq.isInput(e)&&qq.supportedFeatures.ajaxUploading){var t=Array.prototype.slice.call(e.files),n=this;qq.each(t,function(e,t){n._handleNewFile(t,i,d)})}else this._handleNewFile(e,i,d)},this),l=function(){qq.isFileList(e)&&(e=Array.prototype.slice.call(e)),e=[].concat(e)},c=this,d=[];this._currentBatchId=i,e&&(l(),qq.each(e,function(e,t){qq.isFileOrInput(t)?u(t):qq.isBlob(t)?o(t):qq.isObject(t)?t.blob&&t.name?r(t):t.canvas&&t.name&&s(t):t.tagName&&"canvas"===t.tagName.toLowerCase()?a(t):c.log(t+" is not a valid file container! Ignoring!","warn")}),this.log("Received "+d.length+" files."),this._prepareItemsForUpload(d,t,n))},cancel:function(e){this._handler.cancel(e)},cancelAll:function(){var e=[],t=this;qq.extend(e,this._storedIds),qq.each(e,function(e,n){t.cancel(n)}),this._handler.cancelAll()},clearStoredFiles:function(){this._storedIds=[]},continueUpload:function(e){var t=this._uploadData.retrieve({id:e});return!(!qq.supportedFeatures.pause||!this._options.chunking.enabled)&&(t.status===qq.status.PAUSED?(this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.",e,this.getName(e))),this._uploadFile(e),!0):(this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.",e,this.getName(e)),"error"),!1))},deleteFile:function(e){return this._onSubmitDelete(e)},doesExist:function(e){return this._handler.isValid(e)},drawThumbnail:function(e,t,n,i,o){var r,a,s=new qq.Promise;return this._imageGenerator?(r=this._thumbnailUrls[e],a={customResizeFunction:o,maxSize:n>0?n:null,scale:n>0},!i&&qq.supportedFeatures.imagePreviews&&(r=this.getFile(e)),null==r?s.failure({container:t,error:"File or URL not found."}):this._imageGenerator.generate(r,t,a).then(function(e){s.success(e)},function(e,t){s.failure({container:e,error:t||"Problem generating thumbnail"})})):s.failure({container:t,error:"Missing image generator module"}),s},getButton:function(e){return this._getButton(this._buttonIdsForFileIds[e])},getEndpoint:function(e){return this._endpointStore.get(e)},getFile:function(e){return this._handler.getFile(e)||null},getInProgress:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED]}).length},getName:function(e){return this._uploadData.retrieve({id:e}).name},getParentId:function(e){var t=this.getUploads({id:e}),n=null;return t&&void 0!==t.parentId&&(n=t.parentId),n},getResumableFilesData:function(){return this._handler.getResumableFilesData()},getSize:function(e){return this._uploadData.retrieve({id:e}).size},getNetUploads:function(){return this._netUploaded},getRemainingAllowedItems:function(){var e=this._currentItemLimit;return e>0?e-this._netUploadedOrQueued:null},getUploads:function(e){return this._uploadData.retrieve(e)},getUuid:function(e){return this._uploadData.retrieve({id:e}).uuid},log:function(e,t){!this._options.debug||t&&"info"!==t?t&&"info"!==t&&qq.log("[Fine Uploader "+qq.version+"] "+e,t):qq.log("[Fine Uploader "+qq.version+"] "+e)},pauseUpload:function(e){var t=this._uploadData.retrieve({id:e});if(!qq.supportedFeatures.pause||!this._options.chunking.enabled)return!1;if(qq.indexOf([qq.status.UPLOADING,qq.status.UPLOAD_RETRYING],t.status)>=0){if(this._handler.pause(e))return this._uploadData.setStatus(e,qq.status.PAUSED),!0;this.log(qq.format("Unable to pause file ID {} ({}).",e,this.getName(e)),"error")}else this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.",e,this.getName(e)),"error");return!1},reset:function(){this.log("Resetting uploader..."),this._handler.reset(),this._storedIds=[],this._autoRetries=[],this._retryTimeouts=[],this._preventRetries=[],this._thumbnailUrls=[],qq.each(this._buttons,function(e,t){t.reset()}),this._paramsStore.reset(),this._endpointStore.reset(),this._netUploadedOrQueued=0,this._netUploaded=0,this._uploadData.reset(),this._buttonIdsForFileIds=[],this._pasteHandler&&this._pasteHandler.reset(),this._options.session.refreshOnReset&&this._refreshSessionData(),this._succeededSinceLastAllComplete=[],this._failedSinceLastAllComplete=[],this._totalProgress&&this._totalProgress.reset()},retry:function(e){return this._manualRetry(e)},scaleImage:function(e,t){var n=this;return qq.Scaler.prototype.scaleImage(e,t,{log:qq.bind(n.log,n),getFile:qq.bind(n.getFile,n),uploadData:n._uploadData})},setCustomHeaders:function(e,t){this._customHeadersStore.set(e,t)},setDeleteFileCustomHeaders:function(e,t){this._deleteFileCustomHeadersStore.set(e,t)},setDeleteFileEndpoint:function(e,t){this._deleteFileEndpointStore.set(e,t)},setDeleteFileParams:function(e,t){this._deleteFileParamsStore.set(e,t)},setEndpoint:function(e,t){this._endpointStore.set(e,t)},setForm:function(e){this._updateFormSupportAndParams(e)},setItemLimit:function(e){this._currentItemLimit=e},setName:function(e,t){this._uploadData.updateName(e,t)},setParams:function(e,t){this._paramsStore.set(e,t)},setUuid:function(e,t){return this._uploadData.uuidChanged(e,t)},uploadStoredFiles:function(){0===this._storedIds.length?this._itemError("noFilesError"):this._uploadStoredFiles()}},qq.basePrivateApi={_addCannedFile:function(e){var t=this._uploadData.addFile({uuid:e.uuid,name:e.name,size:e.size,status:qq.status.UPLOAD_SUCCESSFUL});return e.deleteFileEndpoint&&this.setDeleteFileEndpoint(e.deleteFileEndpoint,t),e.deleteFileParams&&this.setDeleteFileParams(e.deleteFileParams,t),e.thumbnailUrl&&(this._thumbnailUrls[t]=e.thumbnailUrl),this._netUploaded++,this._netUploadedOrQueued++,t},_annotateWithButtonId:function(e,t){qq.isFile(e)&&(e.qqButtonId=this._getButtonId(t))},_batchError:function(e){this._options.callbacks.onError(null,null,e,void 0)},_createDeleteHandler:function(){var e=this;return new qq.DeleteFileAjaxRequester({method:this._options.deleteFile.method.toUpperCase(),maxConnections:this._options.maxConnections,uuidParamName:this._options.request.uuidName,customHeaders:this._deleteFileCustomHeadersStore,paramsStore:this._deleteFileParamsStore,endpointStore:this._deleteFileEndpointStore,cors:this._options.cors,log:qq.bind(e.log,e),onDelete:function(t){e._onDelete(t),e._options.callbacks.onDelete(t)},onDeleteComplete:function(t,n,i){e._onDeleteComplete(t,n,i),e._options.callbacks.onDeleteComplete(t,n,i)}})},_createPasteHandler:function(){var e=this;return new qq.PasteSupport({targetElement:this._options.paste.targetElement,callbacks:{log:qq.bind(e.log,e),pasteReceived:function(t){e._handleCheckedCallback({name:"onPasteReceived",callback:qq.bind(e._options.callbacks.onPasteReceived,e,t),onSuccess:qq.bind(e._handlePasteSuccess,e,t),identifier:"pasted image"})}}})},_createStore:function(e,t){var n={},i=e,o={},r=t,a=function(e){return qq.isObject(e)?qq.extend({},e):e},s=function(){return qq.isFunction(r)?r():r},u=function(e,t){r&&qq.isObject(t)&&qq.extend(t,s()),o[e]&&qq.extend(t,o[e])};return{set:function(e,t){null==t?(n={},i=a(e)):n[t]=a(e)},get:function(e){var t;return t=null!=e&&n[e]?n[e]:a(i),u(e,t),a(t)},addReadOnly:function(e,t){qq.isObject(n)&&(null===e?qq.isFunction(t)?r=t:(r=r||{},qq.extend(r,t)):(o[e]=o[e]||{},qq.extend(o[e],t)))},remove:function(e){return delete n[e]},reset:function(){n={},o={},i=e}}},_createUploadDataTracker:function(){var e=this;return new qq.UploadData({getName:function(t){return e.getName(t)},getUuid:function(t){return e.getUuid(t)},getSize:function(t){return e.getSize(t)},onStatusChange:function(t,n,i){e._onUploadStatusChange(t,n,i),e._options.callbacks.onStatusChange(t,n,i),e._maybeAllComplete(t,i),e._totalProgress&&setTimeout(function(){e._totalProgress.onStatusChange(t,n,i)},0)}})},_createUploadButton:function(e){function t(){return!!qq.supportedFeatures.ajaxUploading&&(!(i._options.workarounds.iosEmptyVideos&&qq.ios()&&!qq.ios6()&&i._isAllowedExtension(r,".mov"))&&(void 0===e.multiple?i._options.multiple:e.multiple))}var n,i=this,o=e.accept||this._options.validation.acceptFiles,r=e.allowedExtensions||this._options.validation.allowedExtensions;return n=new qq.UploadButton({acceptFiles:o,element:e.element,focusClass:this._options.classes.buttonFocus,folders:e.folders,hoverClass:this._options.classes.buttonHover,ios8BrowserCrashWorkaround:this._options.workarounds.ios8BrowserCrash,multiple:t(),name:this._options.request.inputName,onChange:function(e){i._onInputChange(e)},title:null==e.title?this._options.text.fileInputTitle:e.title}),this._disposeSupport.addDisposer(function(){n.dispose()}),i._buttons.push(n),n},_createUploadHandler:function(e,t){var n=this,i={},o={debug:this._options.debug,maxConnections:this._options.maxConnections,cors:this._options.cors,paramsStore:this._paramsStore,endpointStore:this._endpointStore,chunking:this._options.chunking,resume:this._options.resume,blobs:this._options.blobs,log:qq.bind(n.log,n),preventRetryParam:this._options.retry.preventRetryResponseProperty,onProgress:function(e,t,o,r){o<0||r<0||(i[e]?i[e].loaded===o&&i[e].total===r||(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)):(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)),i[e]={loaded:o,total:r})},onComplete:function(e,t,o,r){delete i[e];var a,s=n.getUploads({id:e}).status;s!==qq.status.UPLOAD_SUCCESSFUL&&s!==qq.status.UPLOAD_FAILED&&(a=n._onComplete(e,t,o,r),a instanceof qq.Promise?a.done(function(){n._options.callbacks.onComplete(e,t,o,r)}):n._options.callbacks.onComplete(e,t,o,r))},onCancel:function(e,t,i){var o=new qq.Promise;return n._handleCheckedCallback({name:"onCancel",callback:qq.bind(n._options.callbacks.onCancel,n,e,t),onFailure:o.failure,onSuccess:function(){i.then(function(){n._onCancel(e,t)}),o.success()},identifier:e}),o},onUploadPrep:qq.bind(this._onUploadPrep,this),onUpload:function(e,t){n._onUpload(e,t),n._options.callbacks.onUpload(e,t)},onUploadChunk:function(e,t,i){n._onUploadChunk(e,i),n._options.callbacks.onUploadChunk(e,t,i)},onUploadChunkSuccess:function(e,t,i,o){n._options.callbacks.onUploadChunkSuccess.apply(n,arguments)},onResume:function(e,t,i){return n._options.callbacks.onResume(e,t,i)},onAutoRetry:function(e,t,i,o){return n._onAutoRetry.apply(n,arguments)},onUuidChanged:function(e,t){n.log("Server requested UUID change from '"+n.getUuid(e)+"' to '"+t+"'"),n.setUuid(e,t)},getName:qq.bind(n.getName,n),getUuid:qq.bind(n.getUuid,n),getSize:qq.bind(n.getSize,n),setSize:qq.bind(n._setSize,n),getDataByUuid:function(e){return n.getUploads({uuid:e})},isQueued:function(e){var t=n.getUploads({id:e}).status;return t===qq.status.QUEUED||t===qq.status.SUBMITTED||t===qq.status.UPLOAD_RETRYING||t===qq.status.PAUSED},getIdsInProxyGroup:n._uploadData.getIdsInProxyGroup,getIdsInBatch:n._uploadData.getIdsInBatch};return qq.each(this._options.request,function(e,t){o[e]=t}),o.customHeaders=this._customHeadersStore,e&&qq.each(e,function(e,t){o[e]=t}),new qq.UploadHandlerController(o,t)},_fileOrBlobRejected:function(e){this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.REJECTED)},_formatSize:function(e){if(0===e)return e+this._options.text.sizeSymbols[0];var t=-1;do e/=1e3,t++;while(e>999);return Math.max(e,.1).toFixed(1)+this._options.text.sizeSymbols[t]},_generateExtraButtonSpecs:function(){var e=this;this._extraButtonSpecs={},qq.each(this._options.extraButtons,function(t,n){var i=n.multiple,o=qq.extend({},e._options.validation,!0),r=qq.extend({},n);void 0===i&&(i=e._options.multiple),r.validation&&qq.extend(o,n.validation,!0),qq.extend(r,{multiple:i,validation:o},!0),e._initExtraButton(r)})},_getButton:function(e){var t=this._extraButtonSpecs[e];return t?t.element:e===this._defaultButtonId?this._options.button:void 0},_getButtonId:function(e){var t,n,i=e;if(i instanceof qq.BlobProxy&&(i=i.referenceBlob),i&&!qq.isBlob(i)){if(qq.isFile(i))return i.qqButtonId;if("input"===i.tagName.toLowerCase()&&"file"===i.type.toLowerCase())return i.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);if(t=i.getElementsByTagName("input"),qq.each(t,function(e,t){if("file"===t.getAttribute("type"))return n=t,!1}),n)return n.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME)}},_getNotFinished:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED,qq.status.SUBMITTING,qq.status.SUBMITTED,qq.status.PAUSED]}).length},_getValidationBase:function(e){var t=this._extraButtonSpecs[e];return t?t.validation:this._options.validation},_getValidationDescriptor:function(e){return e.file instanceof qq.BlobProxy?{name:qq.getFilename(e.file.referenceBlob),size:e.file.referenceBlob.size}:{name:this.getUploads({id:e.id}).name,size:this.getUploads({id:e.id}).size}},_getValidationDescriptors:function(e){var t=this,n=[];return qq.each(e,function(e,i){n.push(t._getValidationDescriptor(i))}),n},_handleCameraAccess:function(){if(this._options.camera.ios&&qq.ios()){var e="image/*;capture=camera",t=this._options.camera.button,n=t?this._getButtonId(t):this._defaultButtonId,i=this._options;n&&n!==this._defaultButtonId&&(i=this._extraButtonSpecs[n]),i.multiple=!1,null===i.validation.acceptFiles?i.validation.acceptFiles=e:i.validation.acceptFiles+=","+e,qq.each(this._buttons,function(e,t){if(t.getButtonId()===n)return t.setMultiple(i.multiple),t.setAcceptFiles(i.acceptFiles),!1})}},_handleCheckedCallback:function(e){var t=this,n=e.callback();return qq.isGenericPromise(n)?(this.log(e.name+" - waiting for "+e.name+" promise to be fulfilled for "+e.identifier),n.then(function(n){t.log(e.name+" promise success for "+e.identifier),e.onSuccess(n)},function(){e.onFailure?(t.log(e.name+" promise failure for "+e.identifier),e.onFailure()):t.log(e.name+" promise failure for "+e.identifier)})):(n!==!1?e.onSuccess(n):e.onFailure?(this.log(e.name+" - return value was 'false' for "+e.identifier+". Invoking failure callback."),e.onFailure()):this.log(e.name+" - return value was 'false' for "+e.identifier+". Will not proceed."),n)},_handleNewFile:function(e,t,n){var i=this,o=qq.getUniqueId(),r=-1,a=qq.getFilename(e),s=e.blob||e,u=this._customNewFileHandler?this._customNewFileHandler:qq.bind(i._handleNewFileGeneric,i);!qq.isInput(s)&&s.size>=0&&(r=s.size),u(s,a,o,r,n,t,this._options.request.uuidName,{uploadData:i._uploadData,paramsStore:i._paramsStore,addFileToHandler:function(e,t){i._handler.add(e,t),i._netUploadedOrQueued++,
+i._trackButton(e)}})},_handleNewFileGeneric:function(e,t,n,i,o,r){var a=this._uploadData.addFile({uuid:n,name:t,size:i,batchId:r});this._handler.add(a,e),this._trackButton(a),this._netUploadedOrQueued++,o.push({id:a,file:e})},_handlePasteSuccess:function(e,t){var n=e.type.split("/")[1],i=t;null==i&&(i=this._options.paste.defaultName),i+="."+n,this.addFiles({name:i,blob:e})},_initExtraButton:function(e){var t=this._createUploadButton({accept:e.validation.acceptFiles,allowedExtensions:e.validation.allowedExtensions,element:e.element,folders:e.folders,multiple:e.multiple,title:e.fileInputTitle});this._extraButtonSpecs[t.getButtonId()]=e},_initFormSupportAndParams:function(){this._formSupport=qq.FormSupport&&new qq.FormSupport(this._options.form,qq.bind(this.uploadStoredFiles,this),qq.bind(this.log,this)),this._formSupport&&this._formSupport.attachedToForm?(this._paramsStore=this._createStore(this._options.request.params,this._formSupport.getFormInputsAsObject),this._options.autoUpload=this._formSupport.newAutoUpload,this._formSupport.newEndpoint&&(this._options.request.endpoint=this._formSupport.newEndpoint)):this._paramsStore=this._createStore(this._options.request.params)},_isDeletePossible:function(){return!(!qq.DeleteFileAjaxRequester||!this._options.deleteFile.enabled)&&(!this._options.cors.expected||(!!qq.supportedFeatures.deleteFileCorsXhr||!(!qq.supportedFeatures.deleteFileCorsXdr||!this._options.cors.allowXdr)))},_isAllowedExtension:function(e,t){var n=!1;return!e.length||(qq.each(e,function(e,i){if(qq.isString(i)){var o=new RegExp("\\."+i+"$","i");if(null!=t.match(o))return n=!0,!1}}),n)},_itemError:function(e,t,n){function i(e,t){a=a.replace(e,t)}var o,r,a=this._options.messages[e],s=[],u=[].concat(t),l=u[0],c=this._getButtonId(n),d=this._getValidationBase(c);return qq.each(d.allowedExtensions,function(e,t){qq.isString(t)&&s.push(t)}),o=s.join(", ").toLowerCase(),i("{file}",this._options.formatFileName(l)),i("{extensions}",o),i("{sizeLimit}",this._formatSize(d.sizeLimit)),i("{minSizeLimit}",this._formatSize(d.minSizeLimit)),r=a.match(/(\{\w+\})/g),null!==r&&qq.each(r,function(e,t){i(t,u[e])}),this._options.callbacks.onError(null,l,a,void 0),a},_manualRetry:function(e,t){if(this._onBeforeManualRetry(e))return this._netUploadedOrQueued++,this._uploadData.setStatus(e,qq.status.UPLOAD_RETRYING),t?t(e):this._handler.retry(e),!0},_maybeAllComplete:function(e,t){var n=this,i=this._getNotFinished();t===qq.status.UPLOAD_SUCCESSFUL?this._succeededSinceLastAllComplete.push(e):t===qq.status.UPLOAD_FAILED&&this._failedSinceLastAllComplete.push(e),0===i&&(this._succeededSinceLastAllComplete.length||this._failedSinceLastAllComplete.length)&&setTimeout(function(){n._onAllComplete(n._succeededSinceLastAllComplete,n._failedSinceLastAllComplete)},0)},_maybeHandleIos8SafariWorkaround:function(){var e=this;if(this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari())throw setTimeout(function(){window.alert(e._options.messages.unsupportedBrowserIos8Safari)},0),new qq.Error(this._options.messages.unsupportedBrowserIos8Safari)},_maybeParseAndSendUploadError:function(e,t,n,i){if(!n.success)if(i&&200!==i.status&&!n.error)this._options.callbacks.onError(e,t,"XHR returned response code "+i.status,i);else{var o=n.error?n.error:this._options.text.defaultResponseError;this._options.callbacks.onError(e,t,o,i)}},_maybeProcessNextItemAfterOnValidateCallback:function(e,t,n,i,o){var r=this;if(t.length>n)if(e||!this._options.validation.stopOnFirstInvalidFile)setTimeout(function(){var e=r._getValidationDescriptor(t[n]),a=r._getButtonId(t[n].file),s=r._getButton(a);r._handleCheckedCallback({name:"onValidate",callback:qq.bind(r._options.callbacks.onValidate,r,e,s),onSuccess:qq.bind(r._onValidateCallbackSuccess,r,t,n,i,o),onFailure:qq.bind(r._onValidateCallbackFailure,r,t,n,i,o),identifier:"Item '"+e.name+"', size: "+e.size})},0);else if(!e)for(;n0&&this._netUploadedOrQueued+1>n?(this._itemError("retryFailTooManyItems"),!1):(this.log("Retrying upload for '"+t+"' (id: "+e+")..."),!0))):(this.log("'"+e+"' is not a valid file ID","error"),!1)},_onCancel:function(e,t){this._netUploadedOrQueued--,clearTimeout(this._retryTimeouts[e]);var n=qq.indexOf(this._storedIds,e);!this._options.autoUpload&&n>=0&&this._storedIds.splice(n,1),this._uploadData.setStatus(e,qq.status.CANCELED)},_onComplete:function(e,t,n,i){return n.success?(n.thumbnailUrl&&(this._thumbnailUrls[e]=n.thumbnailUrl),this._netUploaded++,this._uploadData.setStatus(e,qq.status.UPLOAD_SUCCESSFUL)):(this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.UPLOAD_FAILED),n[this._options.retry.preventRetryResponseProperty]===!0&&(this._preventRetries[e]=!0)),this._maybeParseAndSendUploadError(e,t,n,i),!!n.success},_onDelete:function(e){this._uploadData.setStatus(e,qq.status.DELETING)},_onDeleteComplete:function(e,t,n){var i=this.getName(e);n?(this._uploadData.setStatus(e,qq.status.DELETE_FAILED),this.log("Delete request for '"+i+"' has failed.","error"),void 0===t.withCredentials?this._options.callbacks.onError(e,i,"Delete request failed",t):this._options.callbacks.onError(e,i,"Delete request failed with response code "+t.status,t)):(this._netUploadedOrQueued--,this._netUploaded--,this._handler.expunge(e),this._uploadData.setStatus(e,qq.status.DELETED),this.log("Delete request for '"+i+"' has succeeded."))},_onInputChange:function(e){var t;if(qq.supportedFeatures.ajaxUploading){for(t=0;t0&&this.addFiles(e);qq.each(this._buttons,function(e,t){t.reset()})},_onProgress:function(e,t,n,i){this._totalProgress&&this._totalProgress.onIndividualProgress(e,n,i)},_onSubmit:function(e,t){},_onSubmitCallbackSuccess:function(e,t){this._onSubmit.apply(this,arguments),this._uploadData.setStatus(e,qq.status.SUBMITTED),this._onSubmitted.apply(this,arguments),this._options.autoUpload?(this._options.callbacks.onSubmitted.apply(this,arguments),this._uploadFile(e)):(this._storeForLater(e),this._options.callbacks.onSubmitted.apply(this,arguments))},_onSubmitDelete:function(e,t,n){var i,o=this.getUuid(e);return t&&(i=qq.bind(t,this,e,o,n)),this._isDeletePossible()?(this._handleCheckedCallback({name:"onSubmitDelete",callback:qq.bind(this._options.callbacks.onSubmitDelete,this,e),onSuccess:i||qq.bind(this._deleteHandler.sendDelete,this,e,o,n),identifier:e}),!0):(this.log("Delete request ignored for ID "+e+", delete feature is disabled or request not possible due to CORS on a user agent that does not support pre-flighting.","warn"),!1)},_onSubmitted:function(e){},_onTotalProgress:function(e,t){this._options.callbacks.onTotalProgress(e,t)},_onUploadPrep:function(e){},_onUpload:function(e,t){this._uploadData.setStatus(e,qq.status.UPLOADING)},_onUploadChunk:function(e,t){},_onUploadStatusChange:function(e,t,n){n===qq.status.PAUSED&&clearTimeout(this._retryTimeouts[e])},_onValidateBatchCallbackFailure:function(e){var t=this;qq.each(e,function(e,n){t._fileOrBlobRejected(n.id)})},_onValidateBatchCallbackSuccess:function(e,t,n,i,o){var r,a=this._currentItemLimit,s=this._netUploadedOrQueued;0===a||s<=a?t.length>0?this._handleCheckedCallback({name:"onValidate",callback:qq.bind(this._options.callbacks.onValidate,this,e[0],o),onSuccess:qq.bind(this._onValidateCallbackSuccess,this,t,0,n,i),onFailure:qq.bind(this._onValidateCallbackFailure,this,t,0,n,i),identifier:"Item '"+t[0].file.name+"', size: "+t[0].file.size}):this._itemError("noFilesError"):(this._onValidateBatchCallbackFailure(t),r=this._options.messages.tooManyItemsError.replace(/\{netItems\}/g,s).replace(/\{itemLimit\}/g,a),this._batchError(r))},_onValidateCallbackFailure:function(e,t,n,i){var o=t+1;this._fileOrBlobRejected(e[t].id,e[t].file.name),this._maybeProcessNextItemAfterOnValidateCallback(!1,e,o,n,i)},_onValidateCallbackSuccess:function(e,t,n,i){var o=this,r=t+1,a=this._getValidationDescriptor(e[t]);this._validateFileOrBlobData(e[t],a).then(function(){o._upload(e[t].id,n,i),o._maybeProcessNextItemAfterOnValidateCallback(!0,e,r,n,i)},function(){o._maybeProcessNextItemAfterOnValidateCallback(!1,e,r,n,i)})},_prepareItemsForUpload:function(e,t,n){if(0===e.length)return void this._itemError("noFilesError");var i=this._getValidationDescriptors(e),o=this._getButtonId(e[0].file),r=this._getButton(o);this._handleCheckedCallback({name:"onValidateBatch",callback:qq.bind(this._options.callbacks.onValidateBatch,this,i,r),onSuccess:qq.bind(this._onValidateBatchCallbackSuccess,this,i,e,t,n,r),onFailure:qq.bind(this._onValidateBatchCallbackFailure,this,e),identifier:"batch validation"})},_preventLeaveInProgress:function(){var e=this;this._disposeSupport.attach(window,"beforeunload",function(t){if(e.getInProgress())return t=t||window.event,t.returnValue=e._options.messages.onLeave,e._options.messages.onLeave})},_refreshSessionData:function(){var e=this,t=this._options.session;qq.Session&&null!=this._options.session.endpoint&&(this._session||(qq.extend(t,{cors:this._options.cors}),t.log=qq.bind(this.log,this),t.addFileRecord=qq.bind(this._addCannedFile,this),this._session=new qq.Session(t)),setTimeout(function(){e._session.refresh().then(function(t,n){e._sessionRequestComplete(),e._options.callbacks.onSessionRequestComplete(t,!0,n)},function(t,n){e._options.callbacks.onSessionRequestComplete(t,!1,n)})},0))},_sessionRequestComplete:function(){},_setSize:function(e,t){this._uploadData.updateSize(e,t),this._totalProgress&&this._totalProgress.onNewSize(e)},_shouldAutoRetry:function(e,t,n){var i=this._uploadData.retrieve({id:e});return!!(!this._preventRetries[e]&&this._options.retry.enableAuto&&i.status!==qq.status.PAUSED&&(void 0===this._autoRetries[e]&&(this._autoRetries[e]=0),this._autoRetries[e]0&&s.sizeLimit&&r>s.sizeLimit?(this._itemError("sizeError",o,i),u.failure()):r>0&&r=0}function n(e){var t=!1;return qq.each(t,function(e,n){if(qq.indexOf(["Accept","Accept-Language","Content-Language","Content-Type"],n)<0)return t=!0,!1}),t}function i(e){return w.cors.expected&&void 0===e.withCredentials}function o(){var e;return(window.XMLHttpRequest||window.ActiveXObject)&&(e=qq.createXhrInstance(),void 0===e.withCredentials&&(e=new XDomainRequest,e.onload=function(){},e.onerror=function(){},e.ontimeout=function(){},e.onprogress=function(){})),e}function r(e,t){var n=S[e].xhr;return n||(n=t?t:w.cors.expected?o():qq.createXhrInstance(),S[e].xhr=n),n}function a(e){var t,n=qq.indexOf(v,e),i=w.maxConnections;delete S[e],v.splice(n,1),v.length>=i&&n=0?o.send(qq.obj2url(s,"")):s&&w.contentType&&w.contentType.toLowerCase().indexOf("application/json")>=0?o.send(JSON.stringify(s)):o.send(s),o}function c(e,t,n){var i=w.endpointStore.get(e),o=S[e].addToPath;return void 0!=o&&(i+="/"+o),b&&t&&(i=qq.obj2url(t,i)),n&&(i=qq.obj2url(n,i)),i}function d(e){return function(){4===r(e).readyState&&s(e)}}function q(e){var t=w.onProgress;t&&(r(e).upload.onprogress=function(n){n.lengthComputable&&t(e,n.loaded,n.total)})}function p(e){return function(){s(e)}}function f(e){return function(){s(e,!0)}}function h(e){var o=r(e),a=w.customHeaders,s=S[e].additionalHeaders||{},u=w.method,l={};i(o)||(w.acceptHeader&&o.setRequestHeader("Accept",w.acceptHeader),w.allowXRequestedWithAndCacheControl&&(w.cors.expected&&t()&&!n(a)||(o.setRequestHeader("X-Requested-With","XMLHttpRequest"),o.setRequestHeader("Cache-Control","no-cache"))),!w.contentType||"POST"!==u&&"PUT"!==u||o.setRequestHeader("Content-Type",w.contentType),qq.extend(l,qq.isFunction(a)?a(e):a),qq.extend(l,s),qq.each(l,function(e,t){o.setRequestHeader(e,t)}))}function m(e){return qq.indexOf(w.successfulResponseCodes[w.method],e)>=0}function g(e,t,n,i,o,r,a){S[e]={addToPath:n,additionalParams:i,additionalQueryParams:o,additionalHeaders:r,payload:a};var s=v.push(e);if(s<=w.maxConnections)return l(e,t)}var _,b,v=[],S={},w={acceptHeader:null,validMethods:["PATCH","POST","PUT"],method:"POST",contentType:"application/x-www-form-urlencoded",maxConnections:3,customHeaders:{},endpointStore:{},paramsStore:{},mandatedParams:{},allowXRequestedWithAndCacheControl:!0,successfulResponseCodes:{DELETE:[200,202,204],PATCH:[200,201,202,203,204],POST:[200,201,202,203,204],PUT:[200,201,202,203,204],GET:[200]},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onSend:function(e){},onComplete:function(e,t,n){},onProgress:null};if(qq.extend(w,e),_=w.log,qq.indexOf(w.validMethods,w.method)<0)throw new Error("'"+w.method+"' is not a supported method for this type of request!");b="GET"===w.method||"DELETE"===w.method,qq.extend(this,{initTransport:function(e){var t,n,i,o,r,a;return{withPath:function(e){return t=e,this},withParams:function(e){return n=e,this},withQueryParams:function(e){return a=e,this},withHeaders:function(e){return i=e,this},withPayload:function(e){return o=e,this},withCacheBuster:function(){return r=!0,this},send:function(s){return r&&qq.indexOf(["GET","DELETE"],w.method)>=0&&(n.qqtimestamp=(new Date).getTime()),g(e,s,t,n,a,i,o)}}},canceled:function(e){a(e)}})},qq.UploadHandler=function(e){"use strict";var t=e.proxy,n={},i=t.onCancel,o=t.getName;qq.extend(this,{add:function(e,t){n[e]=t,n[e].temp={}},cancel:function(e){var t=this,r=new qq.Promise,a=i(e,o(e),r);a.then(function(){t.isValid(e)&&(n[e].canceled=!0,t.expunge(e)),r.success()})},expunge:function(e){delete n[e]},getThirdPartyFileId:function(e){return n[e].key},isValid:function(e){return void 0!==n[e]},reset:function(){n={}},_getFileState:function(e){return n[e]},_setThirdPartyFileId:function(e,t){n[e].key=t},_wasCanceled:function(e){return!!n[e].canceled}})},qq.UploadHandlerController=function(e,t){"use strict";var n,i,o,r=this,a=!1,s=!1,u={paramsStore:{},maxConnections:3,chunking:{enabled:!1,multiple:{enabled:!1}},log:function(e,t){},onProgress:function(e,t,n,i){},onComplete:function(e,t,n,i){},onCancel:function(e,t){},onUploadPrep:function(e){},onUpload:function(e,t){},onUploadChunk:function(e,t,n){},onUploadChunkSuccess:function(e,t,n,i){},onAutoRetry:function(e,t,n,i){},onResume:function(e,t,n){},onUuidChanged:function(e,t){},getName:function(e){},setSize:function(e,t){},isQueued:function(e){},getIdsInProxyGroup:function(e){},getIdsInBatch:function(e){}},l={done:function(e,t,n,i){var r=o._getChunkData(e,t);o._getFileState(e).attemptingResume=!1,delete o._getFileState(e).temp.chunkProgress[t],o._getFileState(e).loaded+=r.size,u.onUploadChunkSuccess(e,o._getChunkDataForCallback(r),n,i)},finalize:function(e){var t=u.getSize(e),n=u.getName(e);i("All chunks have been uploaded for "+e+" - finalizing...."),o.finalizeChunks(e).then(function(r,a){i("Finalize successful for "+e);var s=q.normalizeResponse(r,!0);u.onProgress(e,n,t,t),o._maybeDeletePersistedChunkData(e),q.cleanup(e,s,a)},function(t,o){var r=q.normalizeResponse(t,!1);i("Problem finalizing chunks for file ID "+e+" - "+r.error,"error"),r.reset&&l.reset(e),u.onAutoRetry(e,n,r,o)||q.cleanup(e,r,o)})},handleFailure:function(e,t,n,r){var a=u.getName(t);i("Chunked upload request failed for "+t+", chunk "+e),o.clearCachedChunk(t,e);var d,p=q.normalizeResponse(n,!1);p.reset?l.reset(t):(d=qq.indexOf(o._getFileState(t).chunking.inProgress,e),d>=0&&(o._getFileState(t).chunking.inProgress.splice(d,1),o._getFileState(t).chunking.remaining.unshift(e))),o._getFileState(t).temp.ignoreFailure||(s&&(o._getFileState(t).temp.ignoreFailure=!0,i(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.",JSON.stringify(Object.keys(o._getXhrs(t))),JSON.stringify(o._getFileState(t).chunking.inProgress))),qq.each(o._getXhrs(t),function(e,n){i(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ",t,e,n.readyState)),n.abort(),n._cancelled=!0}),o.moveInProgressToRemaining(t),c.free(t,!0)),u.onAutoRetry(t,a,p,r)||q.cleanup(t,p,r))},hasMoreParts:function(e){return!!o._getFileState(e).chunking.remaining.length},nextPart:function(e){var t=o._getFileState(e).chunking.remaining.shift();return t>=o._getTotalChunks(e)&&(t=null),t},reset:function(e){i("Server or callback has ordered chunking effort to be restarted on next attempt for item ID "+e,"error"),o._maybeDeletePersistedChunkData(e),o.reevaluateChunking(e),o._getFileState(e).loaded=0},sendNext:function(e){var t=u.getSize(e),n=u.getName(e),r=l.nextPart(e),a=o._getChunkData(e,r),d=o._getFileState(e).attemptingResume,p=o._getFileState(e).chunking.inProgress||[];null==o._getFileState(e).loaded&&(o._getFileState(e).loaded=0),d&&u.onResume(e,n,a)===!1&&(l.reset(e),r=l.nextPart(e),a=o._getChunkData(e,r),d=!1),null==r&&0===p.length?l.finalize(e):(i(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.",e,r,a.start+1,a.end,t)),u.onUploadChunk(e,n,o._getChunkDataForCallback(a)),p.push(r),o._getFileState(e).chunking.inProgress=p,s&&c.open(e,r),s&&c.available()&&o._getFileState(e).chunking.remaining.length&&l.sendNext(e),0===a.blob.size?(i(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.",r,e),"error"),l.handleFailure(r,e,"File is no longer available",null)):o.uploadChunk(e,r,d).then(function(t,n){i("Chunked upload request succeeded for "+e+", chunk "+r),o.clearCachedChunk(e,r);var a=o._getFileState(e).chunking.inProgress||[],s=q.normalizeResponse(t,!0),u=qq.indexOf(a,r);i(qq.format("Chunk {} for file {} uploaded successfully.",r,e)),l.done(e,r,s,n),u>=0&&a.splice(u,1),o._maybePersistChunkedState(e),l.hasMoreParts(e)||0!==a.length?l.hasMoreParts(e)?l.sendNext(e):i(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}",e,JSON.stringify(a))):l.finalize(e)},function(t,n){l.handleFailure(r,e,t,n)}).done(function(){o.clearXhr(e,r)}))}},c={_open:[],_openChunks:{},_waiting:[],available:function(){var e=u.maxConnections,t=0,n=0;return qq.each(c._openChunks,function(e,i){t++,n+=i.length}),e-(c._open.length-t+n)},free:function(e,t){var n,r=!t,a=qq.indexOf(c._waiting,e),s=qq.indexOf(c._open,e);delete c._openChunks[e],q.getProxyOrBlob(e)instanceof qq.BlobProxy&&(i("Generated blob upload has ended for "+e+", disposing generated blob."),delete o._getFileState(e).file),a>=0?c._waiting.splice(a,1):r&&s>=0&&(c._open.splice(s,1),n=c._waiting.shift(),n>=0&&(c._open.push(n),q.start(n)))},getWaitingOrConnected:function(){var e=[];return qq.each(c._openChunks,function(t,n){n&&n.length&&e.push(parseInt(t))}),qq.each(c._open,function(t,n){c._openChunks[n]||e.push(parseInt(n))}),e=e.concat(c._waiting)},isUsingConnection:function(e){return qq.indexOf(c._open,e)>=0},open:function(e,t){return null==t&&c._waiting.push(e),!!c.available()&&(null==t?(c._waiting.pop(),c._open.push(e)):!function(){var n=c._openChunks[e]||[];n.push(t),c._openChunks[e]=n}(),!0)},reset:function(){c._waiting=[],c._open=[]}},d={send:function(e,t){o._getFileState(e).loaded=0,i("Sending simple upload request for "+e),o.uploadFile(e).then(function(n,o){i("Simple upload request succeeded for "+e);var r=q.normalizeResponse(n,!0),a=u.getSize(e);u.onProgress(e,t,a,a),q.maybeNewUuid(e,r),q.cleanup(e,r,o)},function(n,o){i("Simple upload request failed for "+e);var r=q.normalizeResponse(n,!1);u.onAutoRetry(e,t,r,o)||q.cleanup(e,r,o)})}},q={cancel:function(e){i("Cancelling "+e),u.paramsStore.remove(e),c.free(e)},cleanup:function(e,t,n){var i=u.getName(e);u.onComplete(e,i,t,n),o._getFileState(e)&&o._clearXhrs&&o._clearXhrs(e),c.free(e)},getProxyOrBlob:function(e){return o.getProxy&&o.getProxy(e)||o.getFile&&o.getFile(e)},initHandler:function(){var e=t?qq[t]:qq.traditional,n=qq.supportedFeatures.ajaxUploading?"Xhr":"Form";o=new e[n+"UploadHandler"](u,{getDataByUuid:u.getDataByUuid,getName:u.getName,getSize:u.getSize,getUuid:u.getUuid,log:i,onCancel:u.onCancel,onProgress:u.onProgress,onUuidChanged:u.onUuidChanged}),o._removeExpiredChunkingRecords&&o._removeExpiredChunkingRecords()},isDeferredEligibleForUpload:function(e){return u.isQueued(e)},maybeDefer:function(e,t){return t&&!o.getFile(e)&&t instanceof qq.BlobProxy?(u.onUploadPrep(e),i("Attempting to generate a blob on-demand for "+e),t.create().then(function(t){i("Generated an on-demand blob for "+e),o.updateBlob(e,t),u.setSize(e,t.size),o.reevaluateChunking(e),q.maybeSendDeferredFiles(e)},function(t){var o={};t&&(o.error=t),i(qq.format("Failed to generate blob for ID {}. Error message: {}.",e,t),"error"),u.onComplete(e,u.getName(e),qq.extend(o,n),null),q.maybeSendDeferredFiles(e),c.free(e)}),!1):q.maybeSendDeferredFiles(e)},maybeSendDeferredFiles:function(e){var t=u.getIdsInProxyGroup(e),n=!1;return t&&t.length?(i("Maybe ready to upload proxy group file "+e),qq.each(t,function(t,i){if(q.isDeferredEligibleForUpload(i)&&o.getFile(i))n=i===e,q.now(i);else if(q.isDeferredEligibleForUpload(i))return!1})):(n=!0,q.now(e)),n},maybeNewUuid:function(e,t){void 0!==t.newUuid&&u.onUuidChanged(e,t.newUuid)},normalizeResponse:function(e,t){var n=e;return qq.isObject(e)||(n={},qq.isString(e)&&!t&&(n.error=e)),n.success=t,n},now:function(e){var t=u.getName(e);if(!r.isValid(e))throw new qq.Error(e+" is not a valid file ID to upload!");u.onUpload(e,t),a&&o._shouldChunkThisFile(e)?l.sendNext(e):d.send(e,t)},start:function(e){var t=q.getProxyOrBlob(e);return t?q.maybeDefer(e,t):(q.now(e),!0)}};qq.extend(this,{add:function(e,t){o.add.apply(this,arguments)},upload:function(e){return!!c.open(e)&&q.start(e)},retry:function(e){return s&&(o._getFileState(e).temp.ignoreFailure=!1),c.isUsingConnection(e)?q.start(e):r.upload(e)},cancel:function(e){var t=o.cancel(e);qq.isGenericPromise(t)?t.then(function(){q.cancel(e)}):t!==!1&&q.cancel(e)},cancelAll:function(){var e,t=c.getWaitingOrConnected();if(t.length)for(e=t.length-1;e>=0;e--)r.cancel(t[e]);c.reset()},getFile:function(e){return o.getProxy&&o.getProxy(e)?o.getProxy(e).referenceBlob:o.getFile&&o.getFile(e);
+},isProxied:function(e){return!(!o.getProxy||!o.getProxy(e))},getInput:function(e){if(o.getInput)return o.getInput(e)},reset:function(){i("Resetting upload handler"),r.cancelAll(),c.reset(),o.reset()},expunge:function(e){if(r.isValid(e))return o.expunge(e)},isValid:function(e){return o.isValid(e)},getResumableFilesData:function(){return o.getResumableFilesData?o.getResumableFilesData():[]},getThirdPartyFileId:function(e){if(r.isValid(e))return o.getThirdPartyFileId(e)},pause:function(e){return!!(r.isResumable(e)&&o.pause&&r.isValid(e)&&o.pause(e))&&(c.free(e),o.moveInProgressToRemaining(e),!0)},isResumable:function(e){return!!o.isResumable&&o.isResumable(e)}}),qq.extend(u,e),i=u.log,a=u.chunking.enabled&&qq.supportedFeatures.chunking,s=a&&u.chunking.concurrent.enabled,n=function(){var e={};return e[u.preventRetryParam]=!0,e}(),q.initHandler()},qq.WindowReceiveMessage=function(e){"use strict";var t={log:function(e,t){}},n={};qq.extend(t,e),qq.extend(this,{receiveMessage:function(e,t){var i=function(e){t(e.data)};window.postMessage?n[e]=qq(window).attach("message",i):log("iframe message passing not supported in this browser!","error")},stopReceivingMessages:function(e){if(window.postMessage){var t=n[e];t&&t()}}})},qq.FormUploadHandler=function(e){"use strict";function t(e){delete c[e],q&&(clearTimeout(d[e]),delete d[e],m.stopReceivingMessages(e));var t=document.getElementById(a._getIframeName(e));t&&(t.setAttribute("src","javascript:false;"),qq(t).remove())}function n(e){return e.split("_")[0]}function i(e){var t=qq.toElement("");return t.setAttribute("id",e),t.style.display="none",document.body.appendChild(t),t}function o(e,t){var i=e.id,o=n(i),r=f(o);l[r]=t,c[o]=qq(e).attach("load",function(){a.getInput(o)&&(h("Received iframe load event for CORS upload request (iframe name "+i+")"),d[i]=setTimeout(function(){var e="No valid message received from loaded iframe for iframe name "+i;h(e,"error"),t({error:e})},1e3))}),m.receiveMessage(i,function(e){h("Received the following window message: '"+e+"'");var t,o=(n(i),a._parseJsonResponse(e)),r=o.uuid;r&&l[r]?(h("Handling response for iframe name "+i),clearTimeout(d[i]),delete d[i],a._detachLoadEvent(i),t=l[r],delete l[r],m.stopReceivingMessages(i),t(o)):r||h("'"+e+"' does not contain a UUID - ignoring.")})}var r=e.options,a=this,s=e.proxy,u=qq.getUniqueId(),l={},c={},d={},q=r.isCors,p=r.inputName,f=s.getUuid,h=s.log,m=new qq.WindowReceiveMessage({log:h});qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,n){e.add(t,{input:n}),n.setAttribute("name",p),n.parentNode&&qq(n).remove()},expunge:function(n){t(n),e.expunge(n)},isValid:function(t){return e.isValid(t)&&void 0!==a._getFileState(t).input}}}),qq.extend(this,{getInput:function(e){return a._getFileState(e).input},_attachLoadEvent:function(e,t){var n;q?o(e,t):c[e.id]=qq(e).attach("load",function(){if(h("Received response for "+e.id),e.parentNode){try{if(e.contentDocument&&e.contentDocument.body&&"false"==e.contentDocument.body.innerHTML)return}catch(e){h("Error when attempting to access iframe during handling of upload response ("+e.message+")","error"),n={success:!1}}t(n)}})},_createIframe:function(e){var t=a._getIframeName(e);return i(t)},_detachLoadEvent:function(e){void 0!==c[e]&&(c[e](),delete c[e])},_getIframeName:function(e){return e+"_"+u},_initFormForUpload:function(e){var t=e.method,n=e.endpoint,i=e.params,o=e.paramsInBody,r=e.targetName,a=qq.toElement(""),s=n;return o?qq.obj2Inputs(i,a):s=qq.obj2url(i,n),a.setAttribute("action",s),a.setAttribute("target",r),a.style.display="none",document.body.appendChild(a),a},_parseJsonResponse:function(e){var t={};try{t=qq.parseJson(e)}catch(e){h("Error when attempting to parse iframe upload response ("+e.message+")","error")}return t}})},qq.XhrUploadHandler=function(e){"use strict";function t(e){qq.each(n._getXhrs(e),function(t,i){var o=n._getAjaxRequester(e,t);i.onreadystatechange=null,i.upload.onprogress=null,i.abort(),o&&o.canceled&&o.canceled(e)})}var n=this,i=e.options.namespace,o=e.proxy,r=e.options.chunking,a=e.options.resume,s=r&&e.options.chunking.enabled&&qq.supportedFeatures.chunking,u=a&&e.options.resume.enabled&&s&&qq.supportedFeatures.resume,l=o.getName,c=o.getSize,d=o.getUuid,q=o.getEndpoint,p=o.getDataByUuid,f=o.onUuidChanged,h=o.onProgress,m=o.log;qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,i){if(qq.isFile(i)||qq.isBlob(i))e.add(t,{file:i});else{if(!(i instanceof qq.BlobProxy))throw new Error("Passed obj is not a File, Blob, or proxy");e.add(t,{proxy:i})}n._initTempState(t),u&&n._maybePrepareForResume(t)},expunge:function(i){t(i),n._maybeDeletePersistedChunkData(i),n._clearXhrs(i),e.expunge(i)}}}),qq.extend(this,{clearCachedChunk:function(e,t){delete n._getFileState(e).temp.cachedChunks[t]},clearXhr:function(e,t){var i=n._getFileState(e).temp;i.xhrs&&delete i.xhrs[t],i.ajaxRequesters&&delete i.ajaxRequesters[t]},finalizeChunks:function(e,t){var i=n._getTotalChunks(e)-1,o=n._getXhr(e,i);return t?(new qq.Promise).success(t(o),o):(new qq.Promise).success({},o)},getFile:function(e){return n.isValid(e)&&n._getFileState(e).file},getProxy:function(e){return n.isValid(e)&&n._getFileState(e).proxy},getResumableFilesData:function(){var e=[];return n._iterateResumeRecords(function(t,i){n.moveInProgressToRemaining(null,i.chunking.inProgress,i.chunking.remaining);var o={name:i.name,remaining:i.chunking.remaining,size:i.size,uuid:i.uuid};i.key&&(o.key=i.key),e.push(o)}),e},isResumable:function(e){return!!r&&n.isValid(e)&&!n._getFileState(e).notResumable},moveInProgressToRemaining:function(e,t,i){var o=t||n._getFileState(e).chunking.inProgress,r=i||n._getFileState(e).chunking.remaining;o&&(m(qq.format("Moving these chunks from in-progress {}, to remaining.",JSON.stringify(o))),o.reverse(),qq.each(o,function(e,t){r.unshift(t)}),o.length=0)},pause:function(e){if(n.isValid(e))return m(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.",e,l(e))),n._getFileState(e).paused=!0,t(e),!0},reevaluateChunking:function(e){if(r&&n.isValid(e)){var t,i,o=n._getFileState(e);if(delete o.chunking,o.chunking={},t=n._getTotalChunks(e),t>1||r.mandatory){for(o.chunking.enabled=!0,o.chunking.parts=t,o.chunking.remaining=[],i=0;i=o?o:s+i,l=n._getTotalChunks(e),d=this._getFileState(e).temp.cachedChunks,q=d[t]||qq.sliceBlob(a,s,u);return d[t]=q,{part:t,start:s,end:u,count:l,blob:q,size:u-s}},_getChunkDataForCallback:function(e){return{partIndex:e.part,startByte:e.start+1,endByte:e.end,totalParts:e.count}},_getLocalStorageId:function(e){var t="5.0",n=l(e),o=c(e),a=r.partSize,s=q(e);return qq.format("qq{}resume{}-{}-{}-{}-{}",i,t,n,o,a,s)},_getMimeType:function(e){return n.getFile(e).type},_getPersistableData:function(e){return n._getFileState(e).chunking},_getTotalChunks:function(e){if(r){var t=c(e),n=r.partSize;return Math.ceil(t/n)}},_getXhr:function(e,t){var i=null==t?-1:t;return n._getFileState(e).temp.xhrs[i]},_getXhrs:function(e){return n._getFileState(e).temp.xhrs},_iterateResumeRecords:function(e){u&&qq.each(localStorage,function(t,n){if(0===t.indexOf(qq.format("qq{}resume",i))){var o=JSON.parse(n);e(t,o)}})},_initTempState:function(e){n._getFileState(e).temp={ajaxRequesters:{},chunkProgress:{},xhrs:{},cachedChunks:{}}},_markNotResumable:function(e){n._getFileState(e).notResumable=!0},_maybeDeletePersistedChunkData:function(e){var t;return!!(u&&n.isResumable(e)&&(t=n._getLocalStorageId(e),t&&localStorage.getItem(t)))&&(localStorage.removeItem(t),!0)},_maybePrepareForResume:function(e){var t,i,o=n._getFileState(e);u&&void 0===o.key&&(t=n._getLocalStorageId(e),i=localStorage.getItem(t),i&&(i=JSON.parse(i),p(i.uuid)?n._markNotResumable(e):(m(qq.format("Identified file with ID {} and name of {} as resumable.",e,l(e))),f(e,i.uuid),o.key=i.key,o.chunking=i.chunking,o.loaded=i.loaded,o.attemptingResume=!0,n.moveInProgressToRemaining(e))))},_maybePersistChunkedState:function(e){var t,i,o=n._getFileState(e);if(u&&n.isResumable(e)){t=n._getLocalStorageId(e),i={name:l(e),size:c(e),uuid:d(e),key:o.key,chunking:o.chunking,loaded:o.loaded,lastUpdated:Date.now()};try{localStorage.setItem(t,JSON.stringify(i))}catch(t){m(qq.format("Unable to save resume data for '{}' due to error: '{}'.",e,t.toString()),"warn")}}},_registerProgressHandler:function(e,t,i){var o=n._getXhr(e,t),r=l(e),a={simple:function(t,n){var i=c(e);t===n?h(e,r,i,i):h(e,r,t>=i?i-1:t,i)},chunked:function(o,a){var s=n._getFileState(e).temp.chunkProgress,u=n._getFileState(e).loaded,l=o,d=a,q=c(e),p=l-(d-i),f=u;s[t]=p,qq.each(s,function(e,t){f+=t}),h(e,r,f,q)}};o.upload.onprogress=function(e){if(e.lengthComputable){var t=null==i?"simple":"chunked";a[t](e.loaded,e.total)}}},_registerXhr:function(e,t,i,o){var r=null==t?-1:t,a=n._getFileState(e).temp;return a.xhrs=a.xhrs||{},a.ajaxRequesters=a.ajaxRequesters||{},a.xhrs[r]=i,o&&(a.ajaxRequesters[r]=o),i},_removeExpiredChunkingRecords:function(){var e=a.recordsExpireIn;n._iterateResumeRecords(function(t,n){var i=new Date(n.lastUpdated);i.setDate(i.getDate()+e),i.getTime()<=Date.now()&&(m("Removing expired resume record with key "+t),localStorage.removeItem(t))})},_shouldChunkThisFile:function(e){var t=n._getFileState(e);return t.chunking||n.reevaluateChunking(e),t.chunking.enabled}})},qq.DeleteFileAjaxRequester=function(e){"use strict";function t(){return"POST"===i.method.toUpperCase()?{_method:"DELETE"}:{}}var n,i={method:"DELETE",uuidParamName:"qquuid",endpointStore:{},maxConnections:3,customHeaders:function(e){return{}},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onDelete:function(e){},onDeleteComplete:function(e,t,n){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["POST","DELETE"],method:i.method,endpointStore:i.endpointStore,paramsStore:i.paramsStore,mandatedParams:t(),maxConnections:i.maxConnections,customHeaders:function(e){return i.customHeaders.get(e)},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete,cors:i.cors})),qq.extend(this,{sendDelete:function(e,t,o){var r=o||{};i.log("Submitting delete file request for "+e),"DELETE"===i.method?n.initTransport(e).withPath(t).withParams(r).send():(r[i.uuidParamName]=t,n.initTransport(e).withParams(r).send())}})},function(){function e(e){var t,n=e.naturalWidth,i=e.naturalHeight,o=document.createElement("canvas");return n*i>1048576&&(o.width=o.height=1,t=o.getContext("2d"),t.drawImage(e,-n+1,0),0===t.getImageData(0,0,1,1).data[3])}function t(e,t,n){var i,o,r,a,s=document.createElement("canvas"),u=0,l=n,c=n;for(s.width=1,s.height=n,i=s.getContext("2d"),i.drawImage(e,0,0),o=i.getImageData(0,0,1,n).data;c>u;)r=o[4*(c-1)+3],0===r?l=c:u=c,c=l+u>>1;return a=c/n,0===a?1:a}function n(e,t,n,i){var r=document.createElement("canvas"),a=n.mime||"image/jpeg",s=new qq.Promise;return o(e,t,r,n,i).then(function(){s.success(r.toDataURL(a,n.quality||.8))}),s}function i(e){var t=5241e3;if(!qq.ios())throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");if(e.origHeight*e.origWidth>t)return{newHeight:Math.round(Math.sqrt(t*(e.origHeight/e.origWidth))),newWidth:Math.round(Math.sqrt(t*(e.origWidth/e.origHeight)))}}function o(n,o,s,u,l){var c,d=n.naturalWidth,q=n.naturalHeight,p=u.width,f=u.height,h=s.getContext("2d"),m=new qq.Promise;return h.save(),u.resize?r({blob:o,canvas:s,image:n,imageHeight:q,imageWidth:d,orientation:u.orientation,resize:u.resize,targetHeight:f,targetWidth:p}):(qq.supportedFeatures.unlimitedScaledImageSize||(c=i({origWidth:p,origHeight:f}),c&&(qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h",p,f,c.newWidth,c.newHeight),"warn"),p=c.newWidth,f=c.newHeight)),a(s,p,f,u.orientation),qq.ios()?!function(){e(n)&&(d/=2,q/=2);var i,o,r,a=1024,s=document.createElement("canvas"),u=l?t(n,d,q):1,c=Math.ceil(a*p/d),m=Math.ceil(a*f/q/u),g=0,_=0;for(s.width=s.height=a,i=s.getContext("2d");gc&&(u=c,l=s*u/a<<0),d&&l>d&&(l=d,u=a*l/s<<0),i={width:u,height:l},qq.each(t,function(e,t){i[e]=t}),"img"===p?!function(){var t=e.src;n(r.srcImage,r.blob,i,q).then(function(n){e.src=n,t===e.src&&e.onload()})}():"canvas"===p&&o(this.srcImage,this.blob,e,i,q),void("function"==typeof this.onrender&&this.onrender(e)))},qq.MegaPixImage=s}(),qq.ImageGenerator=function(e){"use strict";function t(e){return"img"===e.tagName.toLowerCase()}function n(e){return"canvas"===e.tagName.toLowerCase()}function i(){return void 0!==(new Image).crossOrigin}function o(){var e=document.createElement("canvas");return e.getContext&&e.getContext("2d")}function r(e){var t=e.split("/"),n=t[t.length-1].split("?")[0],i=qq.getExtension(n);switch(i=i&&i.toLowerCase()){case"jpeg":case"jpg":return"image/jpeg";case"png":return"image/png";case"bmp":return"image/bmp";case"gif":return"image/gif";case"tiff":case"tif":return"image/tiff"}}function a(e){var t,n,i,o=document.createElement("a");return o.href=e,t=o.protocol,i=o.port,n=o.hostname,t.toLowerCase()!==window.location.protocol.toLowerCase()||(n.toLowerCase()!==window.location.hostname.toLowerCase()||i!==window.location.port&&!qq.ie())}function s(t,n){t.onload=function(){t.onload=null,t.onerror=null,n.success(t)},t.onerror=function(){t.onload=null,t.onerror=null,e("Problem drawing thumbnail!","error"),n.failure(t,"Problem drawing thumbnail!")}}function u(e,t){e.qqImageRendered=function(){t.success(e)}}function l(i,o){var r=t(i)||n(i);return t(i)?s(i,o):n(i)?u(i,o):(o.failure(i),e(qq.format("Element container of type {} is not supported!",i.tagName),"error")),r}function c(t,n,i){var o=new qq.Promise,r=new qq.Identify(t,e),a=i.maxSize,s=null==i.orient||i.orient,u=function(){n.onerror=null,n.onload=null,e("Could not render preview, file may be too large!","error"),o.failure(n,"Browser cannot render image!")};return r.isPreviewable().then(function(r){var c={parse:function(){return(new qq.Promise).success()}},d=s?new qq.Exif(t,e):c,q=new qq.MegaPixImage(t,u);l(n,o)&&d.parse().then(function(e){var t=e&&e.Orientation;q.render(n,{maxWidth:a,maxHeight:a,orientation:t,mime:r,resize:i.customResizeFunction})},function(t){e(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.",t)),q.render(n,{maxWidth:a,maxHeight:a,mime:r,resize:i.customResizeFunction})})},function(){e("Not previewable"),o.failure(n,"Not previewable")}),o}function d(e,t,n,i,o){var s=new Image,u=new qq.Promise;l(s,u),a(e)&&(s.crossOrigin="anonymous"),s.src=e,u.then(function(){l(t,n);var a=new qq.MegaPixImage(s);a.render(t,{maxWidth:i,maxHeight:i,mime:r(e),resize:o})},n.failure)}function q(e,t,n,i){l(t,n),qq(t).css({maxWidth:i+"px",maxHeight:i+"px"}),t.src=e}function p(e,r,s){var u=new qq.Promise,c=s.scale,p=c?s.maxSize:null;return c&&t(r)?o()?a(e)&&!i()?q(e,r,u,p):d(e,r,u,p):q(e,r,u,p):n(r)?d(e,r,u,p):l(r,u)&&(r.src=e),u}qq.extend(this,{generate:function(t,n,i){return qq.isString(t)?(e("Attempting to update thumbnail based on server response."),p(t,n,i||{})):(e("Attempting to draw client-side image preview."),c(t,n,i||{}))}}),this._testing={},this._testing.isImg=t,this._testing.isCanvas=n,this._testing.isCrossOrigin=a,this._testing.determineMimeOfFileName=r},qq.Exif=function(e,t){"use strict";function n(e){for(var t=0,n=0;e.length>0;)t+=parseInt(e.substring(0,2),16)*Math.pow(2,n),e=e.substring(2,e.length),n+=8;return t}function i(t,n){var o=t,r=n;return void 0===o&&(o=2,r=new qq.Promise),qq.readBlobToHex(e,o,4).then(function(e){var t,n=/^ffe([0-9])/.exec(e);n?"1"!==n[1]?(t=parseInt(e.slice(4,8),16),i(o+t+2,r)):r.success(o):r.failure("No EXIF header to be found!")}),r}function o(){var t=new qq.Promise;return qq.readBlobToHex(e,0,6).then(function(e){0!==e.indexOf("ffd8")?t.failure("Not a valid JPEG!"):i().then(function(e){t.success(e)},function(e){t.failure(e)})}),t}function r(t){var n=new qq.Promise;return qq.readBlobToHex(e,t+10,2).then(function(e){n.success("4949"===e)}),n}function a(t,i){var o=new qq.Promise;return qq.readBlobToHex(e,t+18,2).then(function(e){return i?o.success(n(e)):void o.success(parseInt(e,16))}),o}function s(t,n){var i=t+20,o=12*n;return qq.readBlobToHex(e,i,o)}function u(e){for(var t=[],n=0;n+24<=e.length;)t.push(e.slice(n,n+24)),n+=24;return t}function l(e,t){var i=16,o=qq.extend([],c),r={};return qq.each(t,function(t,a){var s,u,l,c=a.slice(0,4),q=e?n(c):parseInt(c,16),p=o.indexOf(q);if(p>=0&&(u=d[q].name,l=d[q].bytes,s=a.slice(i,i+2*l),r[u]=e?n(s):parseInt(s,16),o.splice(p,1)),0===o.length)return!1}),r}var c=[274],d={274:{name:"Orientation",bytes:2}};qq.extend(this,{parse:function(){var n=new qq.Promise,i=function(e){t(qq.format("EXIF header parse failed: '{}' ",e)),n.failure(e)};return o().then(function(o){t(qq.format("Moving forward with EXIF header parsing for '{}'",void 0===e.name?"blob":e.name)),r(o).then(function(e){t(qq.format("EXIF Byte order is {} endian",e?"little":"big")),a(o,e).then(function(r){t(qq.format("Found {} APP1 directory entries",r)),s(o,r).then(function(i){var o=u(i),r=l(e,o);t("Successfully parsed some EXIF tags"),n.success(r)},i)},i)},i)},i),n}}),this._testing={},this._testing.parseLittleEndian=n},qq.Identify=function(e,t){"use strict";function n(e,t){var n=!1,i=[].concat(e);return qq.each(i,function(e,i){if(0===t.indexOf(i))return n=!0,!1}),n}qq.extend(this,{isPreviewable:function(){var i=this,o=new qq.Promise,r=!1,a=void 0===e.name?"blob":e.name;return t(qq.format("Attempting to determine if {} can be rendered in this browser",a)),t("First pass: check type attribute of blob object."),this.isPreviewableSync()?(t("Second pass: check for magic bytes in file header."),qq.readBlobToHex(e,0,4).then(function(e){qq.each(i.PREVIEWABLE_MIME_TYPES,function(t,i){if(n(i,e))return("image/tiff"!==t||qq.supportedFeatures.tiffPreviews)&&(r=!0,o.success(t)),!1}),t(qq.format("'{}' is {} able to be rendered in this browser",a,r?"":"NOT")),r||o.failure()},function(){t("Error reading file w/ name '"+a+"'. Not able to be rendered in this browser."),o.failure()})):o.failure(),o},isPreviewableSync:function(){var n=e.type,i=qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES),n)>=0,o=!1,r=void 0===e.name?"blob":e.name;return i&&(o="image/tiff"!==n||qq.supportedFeatures.tiffPreviews),!o&&t(r+" is not previewable in this browser per the blob's type attr"),o}})},qq.Identify.prototype.PREVIEWABLE_MIME_TYPES={"image/jpeg":"ffd8ff","image/gif":"474946","image/png":"89504e","image/bmp":"424d","image/tiff":["49492a00","4d4d002a"]},qq.ImageValidation=function(e,t){"use strict";function n(e){var t=!1;return qq.each(e,function(e,n){if(n>0)return t=!0,!1}),t}function i(){var n=new qq.Promise;return new qq.Identify(e,t).isPreviewable().then(function(){var i=new Image,o=window.URL&&window.URL.createObjectURL?window.URL:window.webkitURL&&window.webkitURL.createObjectURL?window.webkitURL:null;o?(i.onerror=function(){t("Cannot determine dimensions for image. May be too large.","error"),n.failure()},i.onload=function(){n.success({width:this.width,height:this.height})},i.src=o.createObjectURL(e)):(t("No createObjectURL function available to generate image URL!","error"),n.failure())},n.failure),n}function o(e,t){var n;return qq.each(e,function(e,i){if(i>0){var o=/(max|min)(Width|Height)/.exec(e),r=o[2].charAt(0).toLowerCase()+o[2].slice(1),a=t[r];switch(o[1]){case"min":if(ai)return n=e,!1}}}),n}this.validate=function(e){var r=new qq.Promise;return t("Attempting to validate image."),n(e)?i().then(function(t){var n=o(e,t);n?r.failure(n):r.success()},r.success):r.success(),r}},qq.Session=function(e){"use strict";function t(e){return!!qq.isArray(e)||void i.log("Session response is not an array.","error")}function n(e,n,o,r){var a=!1;n=n&&t(e),n&&qq.each(e,function(e,t){if(null==t.uuid)a=!0,i.log(qq.format("Session response item {} did not include a valid UUID - ignoring.",e),"error");else if(null==t.name)a=!0,i.log(qq.format("Session response item {} did not include a valid name - ignoring.",e),"error");else try{return i.addFileRecord(t),!0}catch(e){a=!0,i.log(e.message,"error")}return!1}),r[n&&!a?"success":"failure"](e,o)}var i={endpoint:null,params:{},customHeaders:{},cors:{},addFileRecord:function(e){},log:function(e,t){}};qq.extend(i,e,!0),this.refresh=function(){var e=new qq.Promise,t=function(t,i,o){n(t,i,o,e)},o=qq.extend({},i),r=new qq.SessionAjaxRequester(qq.extend(o,{onComplete:t}));return r.queryServer(),e}},qq.SessionAjaxRequester=function(e){"use strict";function t(e,t,n){var o=null;if(null!=t.responseText)try{o=qq.parseJson(t.responseText)}catch(e){i.log("Problem parsing session response: "+e.message,"error"),n=!0}i.onComplete(o,!n,t)}var n,i={endpoint:null,customHeaders:{},params:{},cors:{expected:!1,sendCredentials:!1},onComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",endpointStore:{get:function(){return i.endpoint}},customHeaders:i.customHeaders,log:i.log,onComplete:t,cors:i.cors})),qq.extend(this,{queryServer:function(){var e=qq.extend({},i.params);i.log("Session query request."),n.initTransport("sessionRefresh").withParams(e).withCacheBuster().send()}})},qq.Scaler=function(e,t){"use strict";var n=e.customResizer,i=e.sendOriginal,o=e.orient,r=e.defaultType,a=e.defaultQuality/100,s=e.failureText,u=e.includeExif,l=this._getSortedSizes(e.sizes);qq.extend(this,{enabled:qq.supportedFeatures.scaling&&l.length>0,getFileRecords:function(e,c,d){var q=this,p=[],f=d.blob?d.blob:d,h=new qq.Identify(f,t);return h.isPreviewableSync()?(qq.each(l,function(e,i){var l=q._determineOutputType({defaultType:r,requestedType:i.type,refType:f.type});p.push({uuid:qq.getUniqueId(),name:q._getName(c,{name:i.name,type:l,refType:f.type}),blob:new qq.BlobProxy(f,qq.bind(q._generateScaledImage,q,{customResizeFunction:n,maxSize:i.maxSize,orient:o,type:l,quality:a,failedText:s,includeExif:u,log:t}))})}),p.push({uuid:e,name:c,size:f.size,blob:i?f:null})):p.push({uuid:e,name:c,size:f.size,blob:f}),p},handleNewFile:function(e,t,n,i,o,r,a,s){var u=this,l=(e.qqButtonId||e.blob&&e.blob.qqButtonId,[]),c=null,d=s.addFileToHandler,q=s.uploadData,p=s.paramsStore,f=qq.getUniqueId();qq.each(u.getFileRecords(n,t,e),function(e,t){var n,i=t.size;t.blob instanceof qq.BlobProxy&&(i=-1),n=q.addFile({uuid:t.uuid,name:t.name,size:i,batchId:r,proxyGroupId:f}),t.blob instanceof qq.BlobProxy?l.push(n):c=n,t.blob?(d(n,t.blob),o.push({id:n,file:t.blob})):q.setStatus(n,qq.status.REJECTED)}),null!==c&&(qq.each(l,function(e,t){var n={qqparentuuid:q.retrieve({id:c}).uuid,qqparentsize:q.retrieve({id:c}).size};n[a]=q.retrieve({id:t}).uuid,q.setParentId(t,c),p.addReadOnly(t,n)}),l.length&&!function(){var e={};e[a]=q.retrieve({id:c}).uuid,p.addReadOnly(c,e)}())}})},qq.extend(qq.Scaler.prototype,{scaleImage:function(e,t,n){"use strict";if(!qq.supportedFeatures.scaling)throw new qq.Error("Scaling is not supported in this browser!");var i=new qq.Promise,o=n.log,r=n.getFile(e),a=n.uploadData.retrieve({id:e}),s=a&&a.name,u=a&&a.uuid,l={customResizer:t.customResizer,sendOriginal:!1,orient:t.orient,defaultType:t.type||null,defaultQuality:t.quality,failedToScaleText:"Unable to scale",sizes:[{name:"",maxSize:t.maxSize}]},c=new qq.Scaler(l,o);return qq.Scaler&&qq.supportedFeatures.imagePreviews&&r?qq.bind(function(){var t=c.getFileRecords(u,s,r)[0];t&&t.blob instanceof qq.BlobProxy?t.blob.create().then(i.success,i.failure):(o(e+" is not a scalable image!","error"),i.failure())},this)():(i.failure(),o("Could not generate requested scaled image for "+e+". Scaling is either not possible in this browser, or the file could not be located.","error")),i},_determineOutputType:function(e){"use strict";var t=e.requestedType,n=e.defaultType,i=e.refType;return n||t?t&&qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES),t)>=0?"image/tiff"===t?qq.supportedFeatures.tiffPreviews?t:n:t:n:"image/jpeg"!==i?"image/png":i},_getName:function(e,t){"use strict";var n=e.lastIndexOf("."),i=t.type||"image/png",o=t.refType,r="",a=qq.getExtension(e),s="";return t.name&&t.name.trim().length&&(s=" ("+t.name+")"),n>=0?(r=e.substr(0,n),o!==i&&(a=i.split("/")[1]),r+=s+"."+a):r=e+s,r},_getSortedSizes:function(e){"use strict";return e=qq.extend([],e),e.sort(function(e,t){return e.maxSize>t.maxSize?1:e.maxSize=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),n=e.split(",")[0].split(":")[1].split(";")[0],i=new ArrayBuffer(t.length),o=new Uint8Array(i),qq.each(t,function(e,t){o[e]=t.charCodeAt(0)}),this._createBlob(i,n)},_createBlob:function(e,t){"use strict";var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})}}),qq.ExifRestorer=function(){var e={};return e.KEY_STR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e.encode64=function(e){var t,n,i,o,r,a="",s="",u="",l=0;do t=e[l++],n=e[l++],s=e[l++],i=t>>2,o=(3&t)<<4|n>>4,r=(15&n)<<2|s>>6,u=63&s,isNaN(n)?r=u=64:isNaN(s)&&(u=64),a=a+this.KEY_STR.charAt(i)+this.KEY_STR.charAt(o)+this.KEY_STR.charAt(r)+this.KEY_STR.charAt(u),t=n=s="",i=o=r=u="";while(le.length)break}return n},e.decode64=function(e){var t,n,i,o,r,a="",s="",u=0,l=[],c=/[^A-Za-z0-9\+\/\=]/g;if(c.exec(e))throw new Error("There were invalid base64 characters in the input text. Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");do i=this.KEY_STR.indexOf(e.charAt(u++)),o=this.KEY_STR.indexOf(e.charAt(u++)),r=this.KEY_STR.indexOf(e.charAt(u++)),s=this.KEY_STR.indexOf(e.charAt(u++)),t=i<<2|o>>4,n=(15&o)<<4|r>>2,a=(3&r)<<6|s,l.push(t),64!=r&&l.push(n),64!=s&&l.push(a),t=n=a="",i=o=r=s="";while(u=0)return n=!1,!1}),n},l=function(e){q(e,-1,-1),delete n[e]},c=function(e,t,n){(0===t.length||u(t,n))&&(s(o,o),this.reset())},d=function(e){var i=t(e);i>0&&(q(e,0,i),n[e]={loaded:0,total:i})},q=function(e,t,r){var a=n[e]?n[e].loaded:0,u=n[e]?n[e].total:0;t===-1&&r===-1?(i-=a,o-=u):(t&&(i+=t-a),r&&(o+=r-u)),s(i,o)};qq.extend(this,{onAllComplete:c,onStatusChange:function(e,t,n){n===qq.status.CANCELED||n===qq.status.REJECTED?l(e):n===qq.status.SUBMITTING&&d(e)},onIndividualProgress:function(e,t,i){q(e,t,i),n[e]={loaded:t,total:i}},onNewSize:function(e){d(e)},reset:function(){n={},i=0,o=0}})},qq.PasteSupport=function(e){"use strict";function t(e){return e.type&&0===e.type.indexOf("image/")}function n(){r=qq(o.targetElement).attach("paste",function(e){var n=e.clipboardData;n&&qq.each(n.items,function(e,n){if(t(n)){var i=n.getAsFile();o.callbacks.pasteReceived(i)}})})}function i(){r&&r()}var o,r;o={targetElement:null,callbacks:{log:function(e,t){},pasteReceived:function(e){}}},qq.extend(o,e),n(),qq.extend(this,{reset:function(){i()}})},qq.FormSupport=function(e,t,n){"use strict";function i(e){e.getAttribute("action")&&(s.newEndpoint=e.getAttribute("action"))}function o(e,t){return!(e.checkValidity&&!e.checkValidity())||(n("Form did not pass validation checks - will not upload.","error"),void t())}function r(e){var n=e.submit;
+qq(e).attach("submit",function(i){i=i||window.event,i.preventDefault?i.preventDefault():i.returnValue=!1,o(e,n)&&t()}),e.submit=function(){o(e,n)&&t()}}function a(e){return e&&(qq.isString(e)&&(e=document.getElementById(e)),e&&(n("Attaching to form element."),i(e),u&&r(e))),e}var s=this,u=e.interceptSubmit,l=e.element,c=e.autoUpload;qq.extend(this,{newEndpoint:null,newAutoUpload:c,attachedToForm:!1,getFormInputsAsObject:function(){return null==l?null:s._form2Obj(l)}}),l=a(l),this.attachedToForm=!!l},qq.extend(qq.FormSupport.prototype,{_form2Obj:function(e){"use strict";var t={},n=function(e){var t=["button","image","reset","submit"];return qq.indexOf(t,e.toLowerCase())<0},i=function(e){return qq.indexOf(["checkbox","radio"],e.toLowerCase())>=0},o=function(e){return!(!i(e.type)||e.checked)||e.disabled&&"hidden"!==e.type.toLowerCase()},r=function(e){var t=null;return qq.each(qq(e).children(),function(e,n){if("option"===n.tagName.toLowerCase()&&n.selected)return t=n.value,!1}),t};return qq.each(e.elements,function(e,i){if(!qq.isInput(i,!0)&&"textarea"!==i.tagName.toLowerCase()||!n(i.type)||o(i)){if("select"===i.tagName.toLowerCase()&&!o(i)){var a=r(i);null!==a&&(t[i.name]=a)}}else t[i.name]=i.value}),t}}),qq.azure=qq.azure||{},qq.azure.util=qq.azure.util||function(){"use strict";return{AZURE_PARAM_PREFIX:"x-ms-meta-",_paramNameMatchesAzureParameter:function(e){switch(e){case"Cache-Control":case"Content-Disposition":case"Content-Encoding":case"Content-MD5":case"x-ms-blob-content-encoding":case"x-ms-blob-content-disposition":case"x-ms-blob-content-md5":case"x-ms-blob-cache-control":return!0;default:return!1}},_getPrefixedParamName:function(e){return qq.azure.util._paramNameMatchesAzureParameter(e)?e:qq.azure.util.AZURE_PARAM_PREFIX+e},getParamsAsHeaders:function(e){var t={};return qq.each(e,function(e,n){var i=qq.azure.util._getPrefixedParamName(e),o=null;qq.isFunction(n)?o=String(n()):qq.isObject(n)?qq.extend(t,qq.azure.util.getParamsAsHeaders(n)):o=String(n),null!==o&&(qq.azure.util._paramNameMatchesAzureParameter(e)?t[i]=o:t[i]=encodeURIComponent(o))}),t},parseAzureError:function(e,t){var n,i,o=new DOMParser,r=o.parseFromString(e,"application/xml"),a=r.getElementsByTagName("Error")[0],s={};if(t("Received error response: "+e,"error"),a)return i=a.getElementsByTagName("Message")[0],i&&(s.message=i.textContent),n=a.getElementsByTagName("Code")[0],n&&(s.code=n.textContent),t("Parsed Azure error: "+JSON.stringify(s),"error"),s}}}(),function(){"use strict";qq.nonTraditionalBasePublicApi={setUploadSuccessParams:function(e,t){this._uploadSuccessParamsStore.set(e,t)},setUploadSuccessEndpoint:function(e,t){this._uploadSuccessEndpointStore.set(e,t)}},qq.nonTraditionalBasePrivateApi={_onComplete:function(e,t,n,i){var o,r,a=!!n.success,s=this,u=arguments,l=this._uploadSuccessEndpointStore.get(e),c=this._options.uploadSuccess.customHeaders,d=this._options.uploadSuccess.method,q=this._options.cors,p=new qq.Promise,f=this._uploadSuccessParamsStore.get(e),h=this._paramsStore.get(e),m=function(t){delete s._failedSuccessRequestCallbacks[e],qq.extend(n,t),qq.FineUploaderBasic.prototype._onComplete.apply(s,u),p.success(t)},g=function(r){var a=o;qq.extend(n,r),n&&n.reset&&(a=null),a?s._failedSuccessRequestCallbacks[e]=a:delete s._failedSuccessRequestCallbacks[e],s._onAutoRetry(e,t,n,i,a)||(qq.FineUploaderBasic.prototype._onComplete.apply(s,u),p.failure(r))};return a&&l?(r=new qq.UploadSuccessAjaxRequester({endpoint:l,method:d,customHeaders:c,cors:q,log:qq.bind(this.log,this)}),qq.extend(f,s._getEndpointSpecificParams(e,n,i),!0),h&&qq.extend(f,h,!0),o=qq.bind(function(){r.sendSuccessRequest(e,f).then(m,g)},s),o(),p):qq.FineUploaderBasic.prototype._onComplete.apply(this,arguments)},_manualRetry:function(e){var t=this._failedSuccessRequestCallbacks[e];return qq.FineUploaderBasic.prototype._manualRetry.call(this,e,t)}}}(),function(){"use strict";qq.azure.FineUploaderBasic=function(e){if(!qq.supportedFeatures.ajaxUploading)throw new qq.Error("Uploading directly to Azure is not possible in this browser.");var t={signature:{endpoint:null,customHeaders:{}},blobProperties:{name:"uuid"},uploadSuccess:{endpoint:null,method:"POST",params:{},customHeaders:{}},chunking:{partSize:4e6,minFileSize:4000001}};qq.extend(t,e,!0),qq.FineUploaderBasic.call(this,t),this._uploadSuccessParamsStore=this._createStore(this._options.uploadSuccess.params),this._uploadSuccessEndpointStore=this._createStore(this._options.uploadSuccess.endpoint),this._failedSuccessRequestCallbacks={},this._cannedBlobNames={}},qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,{getBlobName:function(e){return null==this._cannedBlobNames[e]?this._handler.getThirdPartyFileId(e):this._cannedBlobNames[e]},_getEndpointSpecificParams:function(e){return{blob:this.getBlobName(e),uuid:this.getUuid(e),name:this.getName(e),container:this._endpointStore.get(e)}},_createUploadHandler:function(){return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,{signature:this._options.signature,onGetBlobName:qq.bind(this._determineBlobName,this),deleteBlob:qq.bind(this._deleteBlob,this,!0)},"azure")},_determineBlobName:function(e){var t=this._options.blobProperties.name,n=this.getUuid(e),i=this.getName(e),o=qq.getExtension(i),r=n;if(!qq.isString(t))return t.call(this,e);switch(t){case"uuid":return void 0!==o&&(r+="."+o),(new qq.Promise).success(r);case"filename":return(new qq.Promise).success(i);default:return new qq.Promise.failure("Invalid blobName option value - "+t)}},_addCannedFile:function(e){var t;if(null==e.blobName)throw new qq.Error("Did not find blob name property in server session response. This is required!");return t=qq.FineUploaderBasic.prototype._addCannedFile.apply(this,arguments),this._cannedBlobNames[t]=e.blobName,t},_deleteBlob:function(e,t){var n=this,i={},o={get:function(e){return n._endpointStore.get(e)+"/"+n.getBlobName(e)}},r={get:function(e){return i[e]}},a=function(e,t){i[e]=t,u.send(e)},s=function(t,i,o){e?(n.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS","error"),qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t))):(n._onDeleteComplete(t,o,!0),n._options.callbacks.onDeleteComplete(t,o,!0))},u=new qq.azure.DeleteBlob({endpointStore:r,log:qq.bind(n.log,n),onDelete:function(e){n._onDelete(e),n._options.callbacks.onDelete(e)},onDeleteComplete:function(t,o,r){delete i[t],r&&(e?n.log("Will cancel upload, but failed to remove uncommitted parts from Azure.","error"):qq.azure.util.parseAzureError(o.responseText,qq.bind(n.log,n))),e?(qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t)),n.log("Deleted uncommitted blob chunks for "+t)):(n._onDeleteComplete(t,o,r),n._options.callbacks.onDeleteComplete(t,o,r))}}),l=new qq.azure.GetSas({cors:this._options.cors,customHeaders:this._options.signature.customHeaders,endpointStore:{get:function(){return n._options.signature.endpoint}},restRequestVerb:u.method,log:qq.bind(n.log,n)});l.request(t,o.get(t)).then(qq.bind(a,n,t),qq.bind(s,n,t))},_createDeleteHandler:function(){var e=this;return{sendDelete:function(t,n){e._deleteBlob(!1,t)}}}})}(),qq.azure.XhrUploadHandler=function(e,t){"use strict";function n(e){var t=new qq.Promise;return o(e).then(function(n){var i=a._getMimeType(e),o=a._getPersistableData(e).blockIdEntries;b.putBlockList.send(e,n,o,i,function(t){a._registerXhr(e,null,t,b.putBlockList)}).then(function(n){s("Success combining chunks for id "+e),t.success({},n)},function(n){s("Attempt to combine chunks failed for id "+e,"error"),r(n,t)})},t.failure),t}function i(e){var t=l.get(e),n=new qq.Promise,i=function(i){a._setThirdPartyFileId(e,i),n.success(t+"/"+i)},o=function(e){n.failure(e)};return h(e).then(i,o),n}function o(e,t){var n=null==t?e:e+"."+t,o=new qq.Promise,r=function(e){s("GET SAS request succeeded."),o.success(e)},a=function(e,t){s("GET SAS request failed: "+e,"error"),o.failure({error:"Problem communicating with local server"},t)},u=function(e){b.getSasForPutBlobOrBlock.request(n,e).then(r,a)},l=function(t){s(qq.format("Failed to determine blob name for ID {} - {}",e,t),"error"),o.failure({error:t})};return i(e).then(u,l),o}function r(e,t){var n=qq.azure.util.parseAzureError(e.responseText,s),i="Problem sending file to Azure";t.failure({error:i,azureError:n&&n.message,reset:403===e.status})}var a=this,s=t.log,u=e.cors,l=e.endpointStore,c=e.paramsStore,d=e.signature,q=e.filenameParam,p=e.chunking.minFileSize,f=e.deleteBlob,h=e.onGetBlobName,m=t.getName,g=t.getSize,_=function(e){var t=c.get(e);return t[q]=m(e),t},b={putBlob:new qq.azure.PutBlob({getBlobMetadata:_,log:s}),putBlock:new qq.azure.PutBlock({log:s}),putBlockList:new qq.azure.PutBlockList({getBlobMetadata:_,log:s}),getSasForPutBlobOrBlock:new qq.azure.GetSas({cors:u,customHeaders:d.customHeaders,endpointStore:{get:function(){return d.endpoint}},log:s,restRequestVerb:"PUT"})};qq.extend(this,{uploadChunk:function(e,t){var n=new qq.Promise;return o(e,t).then(function(i){var o=a._createXhr(e,t),u=a._getChunkData(e,t);a._registerProgressHandler(e,t,u.size),a._registerXhr(e,t,o,b.putBlock),b.putBlock.upload(e+"."+t,o,i,t,u.blob).then(function(t){a._getPersistableData(e).blockIdEntries||(a._getPersistableData(e).blockIdEntries=[]),a._getPersistableData(e).blockIdEntries.push(t),s("Put Block call succeeded for "+e),n.success({},o)},function(){s(qq.format("Put Block call failed for ID {} on part {}",e,t),"error"),r(o,n)})},n.failure),n},uploadFile:function(e){var t=new qq.Promise,n=a.getFile(e);return o(e).then(function(i){var o=a._createXhr(e);a._registerProgressHandler(e),b.putBlob.upload(e,o,i,n).then(function(){s("Put Blob call succeeded for "+e),t.success({},o)},function(){s("Put Blob call failed for "+e,"error"),r(o,t)})},t.failure),t}}),qq.extend(this,new qq.XhrUploadHandler({options:qq.extend({namespace:"azure"},e),proxy:qq.extend({getEndpoint:e.endpointStore.get},t)})),qq.override(this,function(e){return{expunge:function(t){var n=a._wasCanceled(t),i=a._getPersistableData(t),o=i&&i.blockIdEntries||[];n&&o.length>0&&f(t),e.expunge(t)},finalizeChunks:function(e){return n(e)},_shouldChunkThisFile:function(t){var n=e._shouldChunkThisFile(t);return n&&g(t)>=p}}})},qq.azure.GetSas=function(e){"use strict";function t(e,t,n){var i=o[e];n?i.failure("Received response code "+t.status,t):t.responseText.length?i.success(t.responseText):i.failure("Empty response.",t),delete o[e]}var n,i={cors:{expected:!1,sendCredentials:!1},customHeaders:{},restRequestVerb:"PUT",endpointStore:null,log:function(e,t){}},o={};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",successfulResponseCodes:{GET:[200]},contentType:null,customHeaders:i.customHeaders,endpointStore:i.endpointStore,cors:i.cors,log:i.log,onComplete:t})),qq.extend(this,{request:function(e,t){var r=new qq.Promise,a=i.restRequestVerb;return i.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.",a,e)),o[e]=r,n.initTransport(e).withParams({bloburi:t,_method:a}).withCacheBuster().send(),r}})},qq.UploadSuccessAjaxRequester=function(e){"use strict";function t(e,t,n){var r,a=i[e],s=t.responseText,u={success:!0},l={success:!1};delete i[e],o.log(qq.format("Received the following response body to an upload success request for id {}: {}",e,s));try{r=qq.parseJson(s),n||r&&(r.error||r.success===!1)?(o.log("Upload success request was rejected by the server.","error"),a.failure(qq.extend(r,l))):(o.log("Upload success was acknowledged by the server."),a.success(qq.extend(r,u)))}catch(t){n?(o.log(qq.format("Your server indicated failure in its upload success request response for id {}!",e),"error"),a.failure(l)):(o.log("Upload success was acknowledged by the server."),a.success(u))}}var n,i=[],o={method:"POST",endpoint:null,maxConnections:3,customHeaders:{},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){}};qq.extend(o,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",method:o.method,endpointStore:{get:function(){return o.endpoint}},paramsStore:o.paramsStore,maxConnections:o.maxConnections,customHeaders:o.customHeaders,log:o.log,onComplete:t,cors:o.cors})),qq.extend(this,{sendSuccessRequest:function(e,t){var r=new qq.Promise;return o.log("Submitting upload success request/notification for "+e),n.initTransport(e).withParams(t).send(),i[e]=r,r}})},qq.azure.DeleteBlob=function(e){"use strict";var t,n="DELETE",i={endpointStore:{},onDelete:function(e){},onDeleteComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[202],e}(),contentType:null,endpointStore:i.endpointStore,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete})),qq.extend(this,{method:n,send:function(e){return i.log("Submitting Delete Blob request for "+e),t.initTransport(e).send()}})},qq.azure.PutBlob=function(e){"use strict";var t,n="PUT",i={getBlobMetadata:function(e){},log:function(e,t){}},o={},r={},a={get:function(e){return o[e]}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[201],e}(),contentType:null,customHeaders:function(e){var t=i.getBlobMetadata(e),n=qq.azure.util.getParamsAsHeaders(t);return n["x-ms-blob-type"]="BlockBlob",n},endpointStore:a,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onComplete:function(e,t,n){var i=r[e];delete o[e],delete r[e],n?i.failure():i.success()}})),qq.extend(this,{method:n,upload:function(e,n,a,s){var u=new qq.Promise;return i.log("Submitting Put Blob request for "+e),r[e]=u,o[e]=a,t.initTransport(e).withPayload(s).withHeaders({"Content-Type":s.type}).send(n),u}})},qq.azure.PutBlock=function(e){"use strict";function t(e){var t=5,n=new Array(t+1).join("0"),i=(n+e).slice(-t);return btoa(i)}var n,i="PUT",o={},r={},a={log:function(e,t){}},s={},u={get:function(e){return s[e]}};qq.extend(a,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),contentType:null,endpointStore:u,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:a.log,onComplete:function(e,t,n){var i=r[e],a=o[e];delete s[e],delete r[e],delete o[e],n?i.failure():i.success(a)}})),qq.extend(this,{method:i,upload:function(e,i,u,l,c){var d=new qq.Promise,q=t(l);return r[e]=d,a.log(qq.format("Submitting Put Block request for {} = part {}",e,l)),s[e]=qq.format("{}&comp=block&blockid={}",u,encodeURIComponent(q)),o[e]={part:l,id:q},n.initTransport(e).withPayload(c).send(i),d}})},qq.azure.PutBlockList=function(e){"use strict";function t(e){var t=document.implementation.createDocument(null,"BlockList",null);return e.sort(function(e,t){return e.part-t.part}),qq.each(e,function(e,n){var i=t.createElement("Latest"),o=t.createTextNode(n.id);i.appendChild(o),qq(t).children()[0].appendChild(i)}),(new XMLSerializer).serializeToString(t)}var n,i="PUT",o={},r={getBlobMetadata:function(e){},log:function(e,t){}},a={},s={get:function(e){return a[e]}};qq.extend(r,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),customHeaders:function(e){var t=r.getBlobMetadata(e);return qq.azure.util.getParamsAsHeaders(t)},contentType:"text/plain",endpointStore:s,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:r.log,onSend:function(){},onComplete:function(e,t,n){var i=o[e];delete a[e],delete o[e],n?i.failure(t):i.success(t)}})),qq.extend(this,{method:i,send:function(e,i,s,u,l){var c,d=new qq.Promise,q=t(s);return o[e]=d,r.log(qq.format("Submitting Put Block List request for {}",e)),a[e]=qq.format("{}&comp=blocklist",i),c=n.initTransport(e).withPayload(q).withHeaders({"x-ms-blob-content-type":u}).send(),l(c),d}})}}(window,window);
+//# sourceMappingURL=azure.fine-uploader.core.min.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.min.js.map b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.min.js.map
new file mode 100644
index 000000000000..babe88b029c9
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.core.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/azure/util.js","../client/js/non-traditional-common/uploader.basic.api.js","../client/js/azure/uploader.basic.js","../client/js/azure/azure.xhr.upload.handler.js","../client/js/azure/get-sas.js","../client/js/uploadsuccess.ajax.requester.js","../client/js/azure/rest/delete-blob.js","../client/js/azure/rest/put-blob.js","../client/js/azure/rest/put-block.js","../client/js/azure/rest/put-block-list.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","intArray","mimeString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","testSupportsFileInputElement","tempInput","supported","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","createInput","BUTTON_ID_ATTR_NAME","buttonId","options","title","self","setMultiple","folders","acceptFiles","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","disposeSupport","onChange","hoverClass","focusClass","ios8BrowserCrashWorkaround","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","byUuid","getDataByStatus","status","statusResults","statuses","index","statusEnum","statusResultIndexes","byStatus","dataIndex","byProxyGroupId","byBatchId","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","params","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","_options","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","fileOrUrl","promiseToReturn","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","callbacks","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","toUpperCase","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","allowedExtensions","accept","validation","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","namespace","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","replacement","extensionsForMessage","placeholderMatch","messages","names","validationBase","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","requestData","dequeue","nextId","queue","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","mandatedParams","optXhr","url","payload","onSend","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","shouldParamsBeInQueryString","contentType","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","acceptHeader","setRequestHeader","allowXRequestedWithAndCacheControl","responseCode","successfulResponseCodes","prepareToSend","validMethods","DELETE","PATCH","POST","PUT","GET","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","preventRetryResponse","controller","chunkingPossible","concurrentChunkingPossible","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","inProgressIdx","responseToReport","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","expungeFile","detachLoadEvents","isCors","postMessageCallbackTimers","corsMessageReceiver","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","onloadCallbacks","onloadCallback","_parseJsonResponse","_detachLoadEvent","formHandlerInstanceId","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","xhrId","ajaxRequester","_getAjaxRequester","chunkFiles","resumeEnabled","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","getMandatedParams","_method","requester","detectSubsampling","img","ctx","iw","naturalWidth","ih","naturalHeight","width","getContext","drawImage","getImageData","detectVerticalSquash","alpha","ratio","sy","ey","py","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","tmpCtx","sx","dx","d","tmpCanvas","vertSquashRatio","dw","dh","dy","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","opt","imgWidth","imgHeight","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","el","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetProtocol","targetHostname","targetPort","targetAnchor","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","TAG_IDS","vals","tagValHex","tagValLength","idHex","tagsToFindIdx","TAG_INFO","274","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","chr1","chr2","enc1","enc2","enc3","output","chr3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","isImage","registerPasteHandler","detachPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","determineNewEndpoint","formEl","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","_form2Obj","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","azure","util","AZURE_PARAM_PREFIX","_paramNameMatchesAzureParameter","_getPrefixedParamName","getParamsAsHeaders","headerName","parseAzureError","codeTag","messageTag","domParser","DOMParser","responseDoc","parseFromString","errorTag","errorDetails","nonTraditionalBasePublicApi","setUploadSuccessParams","_uploadSuccessParamsStore","setUploadSuccessEndpoint","_uploadSuccessEndpointStore","nonTraditionalBasePrivateApi","submitSuccessRequest","successAjaxRequester","onCompleteArgs","successEndpoint","successCustomHeaders","uploadSuccess","successMethod","uploadSuccessParams","fileParams","onSuccessFromServer","successRequestResult","_failedSuccessRequestCallbacks","onFailureFromServer","UploadSuccessAjaxRequester","_getEndpointSpecificParams","sendSuccessRequest","successRequestCallback","signature","blobProperties","minFileSize","_cannedBlobNames","getBlobName","onGetBlobName","_determineBlobName","deleteBlob","_deleteBlob","blobNameOptionValue","fileExtension","blobNameToUse","blobName","relatedToCancel","deleteBlobSasUri","blobUriStore","deleteFileEndpointStore","getSasSuccess","sasUri","getSasFailure","DeleteBlob","getSas","GetSas","restRequestVerb","combineChunks","getSignedUrl","mimeType","blockIdEntries","putBlockList","determineBlobUrl","containerUrl","getBlobNameSuccess","getBlobNameFailure","getSasId","getSasXhr","determineBlobUrlSuccess","blobUrl","getSasForPutBlobOrBlock","determineBlobUrlFailure","azureError","minFileSizeForChunking","getBlobMetadata","putBlob","PutBlob","putBlock","PutBlock","PutBlockList","blockIdEntry","chunkingData","maybePossible","sasResponseReceived","requestPromises","blobUri","requestPromise","restVerb","bloburi","handleSuccessResponse","parsedResponse","pendingRequests","responseJson","successIndicator","failureIndicator","codes","endpoints","promises","endpointHandler","Content-Type","createBlockId","partNum","digits","zeros","paddedPartNum","btoa","blockId","createRequestBody","doc","implementation","createDocument","latestEl","latestTextEl","createTextNode","XMLSerializer","serializeToString","fileMimeType","registerXhrCallback","blockIdsXml","x-ms-blob-content-type"],"mappings":"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","file":"azure.fine-uploader.core.min.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\"\"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.js b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.js
new file mode 100644
index 000000000000..9d51d263a1c2
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.js
@@ -0,0 +1,7930 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+(function(global) {
+ var qq = function(element) {
+ "use strict";
+ return {
+ hide: function() {
+ element.style.display = "none";
+ return this;
+ },
+ attach: function(type, fn) {
+ if (element.addEventListener) {
+ element.addEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.attachEvent("on" + type, fn);
+ }
+ return function() {
+ qq(element).detach(type, fn);
+ };
+ },
+ detach: function(type, fn) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.detachEvent("on" + type, fn);
+ }
+ return this;
+ },
+ contains: function(descendant) {
+ if (!descendant) {
+ return false;
+ }
+ if (element === descendant) {
+ return true;
+ }
+ if (element.contains) {
+ return element.contains(descendant);
+ } else {
+ return !!(descendant.compareDocumentPosition(element) & 8);
+ }
+ },
+ insertBefore: function(elementB) {
+ elementB.parentNode.insertBefore(element, elementB);
+ return this;
+ },
+ remove: function() {
+ element.parentNode.removeChild(element);
+ return this;
+ },
+ css: function(styles) {
+ if (element.style == null) {
+ throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");
+ }
+ if (styles.opacity != null) {
+ if (typeof element.style.opacity !== "string" && typeof element.filters !== "undefined") {
+ styles.filter = "alpha(opacity=" + Math.round(100 * styles.opacity) + ")";
+ }
+ }
+ qq.extend(element.style, styles);
+ return this;
+ },
+ hasClass: function(name, considerParent) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));
+ },
+ addClass: function(name) {
+ if (!qq(element).hasClass(name)) {
+ element.className += " " + name;
+ }
+ return this;
+ },
+ removeClass: function(name) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ element.className = element.className.replace(re, " ").replace(/^\s+|\s+$/g, "");
+ return this;
+ },
+ getByClass: function(className, first) {
+ var candidates, result = [];
+ if (first && element.querySelector) {
+ return element.querySelector("." + className);
+ } else if (element.querySelectorAll) {
+ return element.querySelectorAll("." + className);
+ }
+ candidates = element.getElementsByTagName("*");
+ qq.each(candidates, function(idx, val) {
+ if (qq(val).hasClass(className)) {
+ result.push(val);
+ }
+ });
+ return first ? result[0] : result;
+ },
+ getFirstByClass: function(className) {
+ return qq(element).getByClass(className, true);
+ },
+ children: function() {
+ var children = [], child = element.firstChild;
+ while (child) {
+ if (child.nodeType === 1) {
+ children.push(child);
+ }
+ child = child.nextSibling;
+ }
+ return children;
+ },
+ setText: function(text) {
+ element.innerText = text;
+ element.textContent = text;
+ return this;
+ },
+ clearText: function() {
+ return qq(element).setText("");
+ },
+ hasAttribute: function(attrName) {
+ var attrVal;
+ if (element.hasAttribute) {
+ if (!element.hasAttribute(attrName)) {
+ return false;
+ }
+ return /^false$/i.exec(element.getAttribute(attrName)) == null;
+ } else {
+ attrVal = element[attrName];
+ if (attrVal === undefined) {
+ return false;
+ }
+ return /^false$/i.exec(attrVal) == null;
+ }
+ }
+ };
+ };
+ (function() {
+ "use strict";
+ qq.canvasToBlob = function(canvas, mime, quality) {
+ return qq.dataUriToBlob(canvas.toDataURL(mime, quality));
+ };
+ qq.dataUriToBlob = function(dataUri) {
+ var arrayBuffer, byteString, createBlob = function(data, mime) {
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }, intArray, mimeString;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return createBlob(arrayBuffer, mimeString);
+ };
+ qq.log = function(message, level) {
+ if (window.console) {
+ if (!level || level === "info") {
+ window.console.log(message);
+ } else {
+ if (window.console[level]) {
+ window.console[level](message);
+ } else {
+ window.console.log("<" + level + "> " + message);
+ }
+ }
+ }
+ };
+ qq.isObject = function(variable) {
+ return variable && !variable.nodeType && Object.prototype.toString.call(variable) === "[object Object]";
+ };
+ qq.isFunction = function(variable) {
+ return typeof variable === "function";
+ };
+ qq.isArray = function(value) {
+ return Object.prototype.toString.call(value) === "[object Array]" || value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer;
+ };
+ qq.isItemList = function(maybeItemList) {
+ return Object.prototype.toString.call(maybeItemList) === "[object DataTransferItemList]";
+ };
+ qq.isNodeList = function(maybeNodeList) {
+ return Object.prototype.toString.call(maybeNodeList) === "[object NodeList]" || maybeNodeList.item && maybeNodeList.namedItem;
+ };
+ qq.isString = function(maybeString) {
+ return Object.prototype.toString.call(maybeString) === "[object String]";
+ };
+ qq.trimStr = function(string) {
+ if (String.prototype.trim) {
+ return string.trim();
+ }
+ return string.replace(/^\s+|\s+$/g, "");
+ };
+ qq.format = function(str) {
+ var args = Array.prototype.slice.call(arguments, 1), newStr = str, nextIdxToReplace = newStr.indexOf("{}");
+ qq.each(args, function(idx, val) {
+ var strBefore = newStr.substring(0, nextIdxToReplace), strAfter = newStr.substring(nextIdxToReplace + 2);
+ newStr = strBefore + val + strAfter;
+ nextIdxToReplace = newStr.indexOf("{}", nextIdxToReplace + val.length);
+ if (nextIdxToReplace < 0) {
+ return false;
+ }
+ });
+ return newStr;
+ };
+ qq.isFile = function(maybeFile) {
+ return window.File && Object.prototype.toString.call(maybeFile) === "[object File]";
+ };
+ qq.isFileList = function(maybeFileList) {
+ return window.FileList && Object.prototype.toString.call(maybeFileList) === "[object FileList]";
+ };
+ qq.isFileOrInput = function(maybeFileOrInput) {
+ return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);
+ };
+ qq.isInput = function(maybeInput, notFile) {
+ var evaluateType = function(type) {
+ var normalizedType = type.toLowerCase();
+ if (notFile) {
+ return normalizedType !== "file";
+ }
+ return normalizedType === "file";
+ };
+ if (window.HTMLInputElement) {
+ if (Object.prototype.toString.call(maybeInput) === "[object HTMLInputElement]") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ if (maybeInput.tagName) {
+ if (maybeInput.tagName.toLowerCase() === "input") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ qq.isBlob = function(maybeBlob) {
+ if (window.Blob && Object.prototype.toString.call(maybeBlob) === "[object Blob]") {
+ return true;
+ }
+ };
+ qq.isXhrUploadSupported = function() {
+ var input = document.createElement("input");
+ input.type = "file";
+ return input.multiple !== undefined && typeof File !== "undefined" && typeof FormData !== "undefined" && typeof qq.createXhrInstance().upload !== "undefined";
+ };
+ qq.createXhrInstance = function() {
+ if (window.XMLHttpRequest) {
+ return new XMLHttpRequest();
+ }
+ try {
+ return new ActiveXObject("MSXML2.XMLHTTP.3.0");
+ } catch (error) {
+ qq.log("Neither XHR or ActiveX are supported!", "error");
+ return null;
+ }
+ };
+ qq.isFolderDropSupported = function(dataTransfer) {
+ return dataTransfer.items && dataTransfer.items.length > 0 && dataTransfer.items[0].webkitGetAsEntry;
+ };
+ qq.isFileChunkingSupported = function() {
+ return !qq.androidStock() && qq.isXhrUploadSupported() && (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);
+ };
+ qq.sliceBlob = function(fileOrBlob, start, end) {
+ var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;
+ return slicer.call(fileOrBlob, start, end);
+ };
+ qq.arrayBufferToHex = function(buffer) {
+ var bytesAsHex = "", bytes = new Uint8Array(buffer);
+ qq.each(bytes, function(idx, byt) {
+ var byteAsHexStr = byt.toString(16);
+ if (byteAsHexStr.length < 2) {
+ byteAsHexStr = "0" + byteAsHexStr;
+ }
+ bytesAsHex += byteAsHexStr;
+ });
+ return bytesAsHex;
+ };
+ qq.readBlobToHex = function(blob, startOffset, length) {
+ var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), fileReader = new FileReader(), promise = new qq.Promise();
+ fileReader.onload = function() {
+ promise.success(qq.arrayBufferToHex(fileReader.result));
+ };
+ fileReader.onerror = promise.failure;
+ fileReader.readAsArrayBuffer(initialBlob);
+ return promise;
+ };
+ qq.extend = function(first, second, extendNested) {
+ qq.each(second, function(prop, val) {
+ if (extendNested && qq.isObject(val)) {
+ if (first[prop] === undefined) {
+ first[prop] = {};
+ }
+ qq.extend(first[prop], val, true);
+ } else {
+ first[prop] = val;
+ }
+ });
+ return first;
+ };
+ qq.override = function(target, sourceFn) {
+ var super_ = {}, source = sourceFn(super_);
+ qq.each(source, function(srcPropName, srcPropVal) {
+ if (target[srcPropName] !== undefined) {
+ super_[srcPropName] = target[srcPropName];
+ }
+ target[srcPropName] = srcPropVal;
+ });
+ return target;
+ };
+ qq.indexOf = function(arr, elt, from) {
+ if (arr.indexOf) {
+ return arr.indexOf(elt, from);
+ }
+ from = from || 0;
+ var len = arr.length;
+ if (from < 0) {
+ from += len;
+ }
+ for (;from < len; from += 1) {
+ if (arr.hasOwnProperty(from) && arr[from] === elt) {
+ return from;
+ }
+ }
+ return -1;
+ };
+ qq.getUniqueId = function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
+ return v.toString(16);
+ });
+ };
+ qq.ie = function() {
+ return navigator.userAgent.indexOf("MSIE") !== -1 || navigator.userAgent.indexOf("Trident") !== -1;
+ };
+ qq.ie7 = function() {
+ return navigator.userAgent.indexOf("MSIE 7") !== -1;
+ };
+ qq.ie8 = function() {
+ return navigator.userAgent.indexOf("MSIE 8") !== -1;
+ };
+ qq.ie10 = function() {
+ return navigator.userAgent.indexOf("MSIE 10") !== -1;
+ };
+ qq.ie11 = function() {
+ return qq.ie() && navigator.userAgent.indexOf("rv:11") !== -1;
+ };
+ qq.edge = function() {
+ return navigator.userAgent.indexOf("Edge") >= 0;
+ };
+ qq.safari = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Apple") !== -1;
+ };
+ qq.chrome = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Google") !== -1;
+ };
+ qq.opera = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Opera") !== -1;
+ };
+ qq.firefox = function() {
+ return !qq.edge() && !qq.ie11() && navigator.userAgent.indexOf("Mozilla") !== -1 && navigator.vendor !== undefined && navigator.vendor === "";
+ };
+ qq.windows = function() {
+ return navigator.platform === "Win32";
+ };
+ qq.android = function() {
+ return navigator.userAgent.toLowerCase().indexOf("android") !== -1;
+ };
+ qq.androidStock = function() {
+ return qq.android() && navigator.userAgent.toLowerCase().indexOf("chrome") < 0;
+ };
+ qq.ios6 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 6_") !== -1;
+ };
+ qq.ios7 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 7_") !== -1;
+ };
+ qq.ios8 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_") !== -1;
+ };
+ qq.ios800 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_0 ") !== -1;
+ };
+ qq.ios = function() {
+ return navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("iPod") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1;
+ };
+ qq.iosChrome = function() {
+ return qq.ios() && navigator.userAgent.indexOf("CriOS") !== -1;
+ };
+ qq.iosSafari = function() {
+ return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf("Safari") !== -1;
+ };
+ qq.iosSafariWebView = function() {
+ return qq.ios() && !qq.iosChrome() && !qq.iosSafari();
+ };
+ qq.preventDefault = function(e) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ };
+ qq.toElement = function() {
+ var div = document.createElement("div");
+ return function(html) {
+ div.innerHTML = html;
+ var element = div.firstChild;
+ div.removeChild(element);
+ return element;
+ };
+ }();
+ qq.each = function(iterableItem, callback) {
+ var keyOrIndex, retVal;
+ if (iterableItem) {
+ if (window.Storage && iterableItem.constructor === window.Storage) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isString(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else {
+ for (keyOrIndex in iterableItem) {
+ if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ };
+ qq.bind = function(oldFunc, context) {
+ if (qq.isFunction(oldFunc)) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ return function() {
+ var newArgs = qq.extend([], args);
+ if (arguments.length) {
+ newArgs = newArgs.concat(Array.prototype.slice.call(arguments));
+ }
+ return oldFunc.apply(context, newArgs);
+ };
+ }
+ throw new Error("first parameter must be a function!");
+ };
+ qq.obj2url = function(obj, temp, prefixDone) {
+ var uristrings = [], prefix = "&", add = function(nextObj, i) {
+ var nextTemp = temp ? /\[\]$/.test(temp) ? temp : temp + "[" + i + "]" : i;
+ if (nextTemp !== "undefined" && i !== "undefined") {
+ uristrings.push(typeof nextObj === "object" ? qq.obj2url(nextObj, nextTemp, true) : Object.prototype.toString.call(nextObj) === "[object Function]" ? encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj));
+ }
+ };
+ if (!prefixDone && temp) {
+ prefix = /\?/.test(temp) ? /\?$/.test(temp) ? "" : "&" : "?";
+ uristrings.push(temp);
+ uristrings.push(qq.obj2url(obj));
+ } else if (Object.prototype.toString.call(obj) === "[object Array]" && typeof obj !== "undefined") {
+ qq.each(obj, function(idx, val) {
+ add(val, idx);
+ });
+ } else if (typeof obj !== "undefined" && obj !== null && typeof obj === "object") {
+ qq.each(obj, function(prop, val) {
+ add(val, prop);
+ });
+ } else {
+ uristrings.push(encodeURIComponent(temp) + "=" + encodeURIComponent(obj));
+ }
+ if (temp) {
+ return uristrings.join(prefix);
+ } else {
+ return uristrings.join(prefix).replace(/^&/, "").replace(/%20/g, "+");
+ }
+ };
+ qq.obj2FormData = function(obj, formData, arrayKeyName) {
+ if (!formData) {
+ formData = new FormData();
+ }
+ qq.each(obj, function(key, val) {
+ key = arrayKeyName ? arrayKeyName + "[" + key + "]" : key;
+ if (qq.isObject(val)) {
+ qq.obj2FormData(val, formData, key);
+ } else if (qq.isFunction(val)) {
+ formData.append(key, val());
+ } else {
+ formData.append(key, val);
+ }
+ });
+ return formData;
+ };
+ qq.obj2Inputs = function(obj, form) {
+ var input;
+ if (!form) {
+ form = document.createElement("form");
+ }
+ qq.obj2FormData(obj, {
+ append: function(key, val) {
+ input = document.createElement("input");
+ input.setAttribute("name", key);
+ input.setAttribute("value", val);
+ form.appendChild(input);
+ }
+ });
+ return form;
+ };
+ qq.parseJson = function(json) {
+ if (window.JSON && qq.isFunction(JSON.parse)) {
+ return JSON.parse(json);
+ } else {
+ return eval("(" + json + ")");
+ }
+ };
+ qq.getExtension = function(filename) {
+ var extIdx = filename.lastIndexOf(".") + 1;
+ if (extIdx > 0) {
+ return filename.substr(extIdx, filename.length - extIdx);
+ }
+ };
+ qq.getFilename = function(blobOrFileInput) {
+ if (qq.isInput(blobOrFileInput)) {
+ return blobOrFileInput.value.replace(/.*(\/|\\)/, "");
+ } else if (qq.isFile(blobOrFileInput)) {
+ if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {
+ return blobOrFileInput.fileName;
+ }
+ }
+ return blobOrFileInput.name;
+ };
+ qq.DisposeSupport = function() {
+ var disposers = [];
+ return {
+ dispose: function() {
+ var disposer;
+ do {
+ disposer = disposers.shift();
+ if (disposer) {
+ disposer();
+ }
+ } while (disposer);
+ },
+ attach: function() {
+ var args = arguments;
+ this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));
+ },
+ addDisposer: function(disposeFunction) {
+ disposers.push(disposeFunction);
+ }
+ };
+ };
+ })();
+ (function() {
+ "use strict";
+ if (typeof define === "function" && define.amd) {
+ define(function() {
+ return qq;
+ });
+ } else if (typeof module !== "undefined" && module.exports) {
+ module.exports = qq;
+ } else {
+ global.qq = qq;
+ }
+ })();
+ (function() {
+ "use strict";
+ qq.Error = function(message) {
+ this.message = "[Fine Uploader " + qq.version + "] " + message;
+ };
+ qq.Error.prototype = new Error();
+ })();
+ qq.version = "5.13.0";
+ qq.supportedFeatures = function() {
+ "use strict";
+ var supportsUploading, supportsUploadingBlobs, supportsFileDrop, supportsAjaxFileUploading, supportsFolderDrop, supportsChunking, supportsResume, supportsUploadViaPaste, supportsUploadCors, supportsDeleteFileXdr, supportsDeleteFileCorsXhr, supportsDeleteFileCors, supportsFolderSelection, supportsImagePreviews, supportsUploadProgress;
+ function testSupportsFileInputElement() {
+ var supported = true, tempInput;
+ try {
+ tempInput = document.createElement("input");
+ tempInput.type = "file";
+ qq(tempInput).hide();
+ if (tempInput.disabled) {
+ supported = false;
+ }
+ } catch (ex) {
+ supported = false;
+ }
+ return supported;
+ }
+ function isChrome21OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/) !== undefined;
+ }
+ function isChrome14OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/) !== undefined;
+ }
+ function isCrossOriginXhrSupported() {
+ if (window.XMLHttpRequest) {
+ var xhr = qq.createXhrInstance();
+ return xhr.withCredentials !== undefined;
+ }
+ return false;
+ }
+ function isXdrSupported() {
+ return window.XDomainRequest !== undefined;
+ }
+ function isCrossOriginAjaxSupported() {
+ if (isCrossOriginXhrSupported()) {
+ return true;
+ }
+ return isXdrSupported();
+ }
+ function isFolderSelectionSupported() {
+ return document.createElement("input").webkitdirectory !== undefined;
+ }
+ function isLocalStorageSupported() {
+ try {
+ return !!window.localStorage && qq.isFunction(window.localStorage.setItem);
+ } catch (error) {
+ return false;
+ }
+ }
+ function isDragAndDropSupported() {
+ var span = document.createElement("span");
+ return ("draggable" in span || "ondragstart" in span && "ondrop" in span) && !qq.android() && !qq.ios();
+ }
+ supportsUploading = testSupportsFileInputElement();
+ supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();
+ supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();
+ supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();
+ supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();
+ supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();
+ supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();
+ supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();
+ supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);
+ supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();
+ supportsDeleteFileXdr = isXdrSupported();
+ supportsDeleteFileCors = isCrossOriginAjaxSupported();
+ supportsFolderSelection = isFolderSelectionSupported();
+ supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;
+ supportsUploadProgress = function() {
+ if (supportsAjaxFileUploading) {
+ return !qq.androidStock() && !qq.iosChrome();
+ }
+ return false;
+ }();
+ return {
+ ajaxUploading: supportsAjaxFileUploading,
+ blobUploading: supportsUploadingBlobs,
+ canDetermineSize: supportsAjaxFileUploading,
+ chunking: supportsChunking,
+ deleteFileCors: supportsDeleteFileCors,
+ deleteFileCorsXdr: supportsDeleteFileXdr,
+ deleteFileCorsXhr: supportsDeleteFileCorsXhr,
+ dialogElement: !!window.HTMLDialogElement,
+ fileDrop: supportsFileDrop,
+ folderDrop: supportsFolderDrop,
+ folderSelection: supportsFolderSelection,
+ imagePreviews: supportsImagePreviews,
+ imageValidation: supportsImagePreviews,
+ itemSizeValidation: supportsAjaxFileUploading,
+ pause: supportsChunking,
+ progressBar: supportsUploadProgress,
+ resume: supportsResume,
+ scaling: supportsImagePreviews && supportsUploadingBlobs,
+ tiffPreviews: qq.safari(),
+ unlimitedScaledImageSize: !qq.ios(),
+ uploading: supportsUploading,
+ uploadCors: supportsUploadCors,
+ uploadCustomHeaders: supportsAjaxFileUploading,
+ uploadNonMultipart: supportsAjaxFileUploading,
+ uploadViaPaste: supportsUploadViaPaste
+ };
+ }();
+ qq.isGenericPromise = function(maybePromise) {
+ "use strict";
+ return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));
+ };
+ qq.Promise = function() {
+ "use strict";
+ var successArgs, failureArgs, successCallbacks = [], failureCallbacks = [], doneCallbacks = [], state = 0;
+ qq.extend(this, {
+ then: function(onSuccess, onFailure) {
+ if (state === 0) {
+ if (onSuccess) {
+ successCallbacks.push(onSuccess);
+ }
+ if (onFailure) {
+ failureCallbacks.push(onFailure);
+ }
+ } else if (state === -1) {
+ onFailure && onFailure.apply(null, failureArgs);
+ } else if (onSuccess) {
+ onSuccess.apply(null, successArgs);
+ }
+ return this;
+ },
+ done: function(callback) {
+ if (state === 0) {
+ doneCallbacks.push(callback);
+ } else {
+ callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);
+ }
+ return this;
+ },
+ success: function() {
+ state = 1;
+ successArgs = arguments;
+ if (successCallbacks.length) {
+ qq.each(successCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ return this;
+ },
+ failure: function() {
+ state = -1;
+ failureArgs = arguments;
+ if (failureCallbacks.length) {
+ qq.each(failureCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ return this;
+ }
+ });
+ };
+ qq.BlobProxy = function(referenceBlob, onCreate) {
+ "use strict";
+ qq.extend(this, {
+ referenceBlob: referenceBlob,
+ create: function() {
+ return onCreate(referenceBlob);
+ }
+ });
+ };
+ qq.UploadButton = function(o) {
+ "use strict";
+ var self = this, disposeSupport = new qq.DisposeSupport(), options = {
+ acceptFiles: null,
+ element: null,
+ focusClass: "qq-upload-button-focus",
+ folders: false,
+ hoverClass: "qq-upload-button-hover",
+ ios8BrowserCrashWorkaround: false,
+ multiple: false,
+ name: "qqfile",
+ onChange: function(input) {},
+ title: null
+ }, input, buttonId;
+ qq.extend(options, o);
+ buttonId = qq.getUniqueId();
+ function createInput() {
+ var input = document.createElement("input");
+ input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);
+ input.setAttribute("title", options.title);
+ self.setMultiple(options.multiple, input);
+ if (options.folders && qq.supportedFeatures.folderSelection) {
+ input.setAttribute("webkitdirectory", "");
+ }
+ if (options.acceptFiles) {
+ input.setAttribute("accept", options.acceptFiles);
+ }
+ input.setAttribute("type", "file");
+ input.setAttribute("name", options.name);
+ qq(input).css({
+ position: "absolute",
+ right: 0,
+ top: 0,
+ fontFamily: "Arial",
+ fontSize: qq.ie() && !qq.ie8() ? "3500px" : "118px",
+ margin: 0,
+ padding: 0,
+ cursor: "pointer",
+ opacity: 0
+ });
+ !qq.ie7() && qq(input).css({
+ height: "100%"
+ });
+ options.element.appendChild(input);
+ disposeSupport.attach(input, "change", function() {
+ options.onChange(input);
+ });
+ disposeSupport.attach(input, "mouseover", function() {
+ qq(options.element).addClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "mouseout", function() {
+ qq(options.element).removeClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "focus", function() {
+ qq(options.element).addClass(options.focusClass);
+ });
+ disposeSupport.attach(input, "blur", function() {
+ qq(options.element).removeClass(options.focusClass);
+ });
+ return input;
+ }
+ qq(options.element).css({
+ position: "relative",
+ overflow: "hidden",
+ direction: "ltr"
+ });
+ qq.extend(this, {
+ getInput: function() {
+ return input;
+ },
+ getButtonId: function() {
+ return buttonId;
+ },
+ setMultiple: function(isMultiple, optInput) {
+ var input = optInput || this.getInput();
+ if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {
+ input.setAttribute("multiple", "");
+ } else {
+ if (isMultiple) {
+ input.setAttribute("multiple", "");
+ } else {
+ input.removeAttribute("multiple");
+ }
+ }
+ },
+ setAcceptFiles: function(acceptFiles) {
+ if (acceptFiles !== options.acceptFiles) {
+ input.setAttribute("accept", acceptFiles);
+ }
+ },
+ reset: function() {
+ if (input.parentNode) {
+ qq(input).remove();
+ }
+ qq(options.element).removeClass(options.focusClass);
+ input = null;
+ input = createInput();
+ }
+ });
+ input = createInput();
+ };
+ qq.UploadButton.BUTTON_ID_ATTR_NAME = "qq-button-id";
+ qq.UploadData = function(uploaderProxy) {
+ "use strict";
+ var data = [], byUuid = {}, byStatus = {}, byProxyGroupId = {}, byBatchId = {};
+ function getDataByIds(idOrIds) {
+ if (qq.isArray(idOrIds)) {
+ var entries = [];
+ qq.each(idOrIds, function(idx, id) {
+ entries.push(data[id]);
+ });
+ return entries;
+ }
+ return data[idOrIds];
+ }
+ function getDataByUuids(uuids) {
+ if (qq.isArray(uuids)) {
+ var entries = [];
+ qq.each(uuids, function(idx, uuid) {
+ entries.push(data[byUuid[uuid]]);
+ });
+ return entries;
+ }
+ return data[byUuid[uuids]];
+ }
+ function getDataByStatus(status) {
+ var statusResults = [], statuses = [].concat(status);
+ qq.each(statuses, function(index, statusEnum) {
+ var statusResultIndexes = byStatus[statusEnum];
+ if (statusResultIndexes !== undefined) {
+ qq.each(statusResultIndexes, function(i, dataIndex) {
+ statusResults.push(data[dataIndex]);
+ });
+ }
+ });
+ return statusResults;
+ }
+ qq.extend(this, {
+ addFile: function(spec) {
+ var status = spec.status || qq.status.SUBMITTING, id = data.push({
+ name: spec.name,
+ originalName: spec.name,
+ uuid: spec.uuid,
+ size: spec.size == null ? -1 : spec.size,
+ status: status
+ }) - 1;
+ if (spec.batchId) {
+ data[id].batchId = spec.batchId;
+ if (byBatchId[spec.batchId] === undefined) {
+ byBatchId[spec.batchId] = [];
+ }
+ byBatchId[spec.batchId].push(id);
+ }
+ if (spec.proxyGroupId) {
+ data[id].proxyGroupId = spec.proxyGroupId;
+ if (byProxyGroupId[spec.proxyGroupId] === undefined) {
+ byProxyGroupId[spec.proxyGroupId] = [];
+ }
+ byProxyGroupId[spec.proxyGroupId].push(id);
+ }
+ data[id].id = id;
+ byUuid[spec.uuid] = id;
+ if (byStatus[status] === undefined) {
+ byStatus[status] = [];
+ }
+ byStatus[status].push(id);
+ uploaderProxy.onStatusChange(id, null, status);
+ return id;
+ },
+ retrieve: function(optionalFilter) {
+ if (qq.isObject(optionalFilter) && data.length) {
+ if (optionalFilter.id !== undefined) {
+ return getDataByIds(optionalFilter.id);
+ } else if (optionalFilter.uuid !== undefined) {
+ return getDataByUuids(optionalFilter.uuid);
+ } else if (optionalFilter.status) {
+ return getDataByStatus(optionalFilter.status);
+ }
+ } else {
+ return qq.extend([], data, true);
+ }
+ },
+ reset: function() {
+ data = [];
+ byUuid = {};
+ byStatus = {};
+ byBatchId = {};
+ },
+ setStatus: function(id, newStatus) {
+ var oldStatus = data[id].status, byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);
+ byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);
+ data[id].status = newStatus;
+ if (byStatus[newStatus] === undefined) {
+ byStatus[newStatus] = [];
+ }
+ byStatus[newStatus].push(id);
+ uploaderProxy.onStatusChange(id, oldStatus, newStatus);
+ },
+ uuidChanged: function(id, newUuid) {
+ var oldUuid = data[id].uuid;
+ data[id].uuid = newUuid;
+ byUuid[newUuid] = id;
+ delete byUuid[oldUuid];
+ },
+ updateName: function(id, newName) {
+ data[id].name = newName;
+ },
+ updateSize: function(id, newSize) {
+ data[id].size = newSize;
+ },
+ setParentId: function(targetId, parentId) {
+ data[targetId].parentId = parentId;
+ },
+ getIdsInProxyGroup: function(id) {
+ var proxyGroupId = data[id].proxyGroupId;
+ if (proxyGroupId) {
+ return byProxyGroupId[proxyGroupId];
+ }
+ return [];
+ },
+ getIdsInBatch: function(id) {
+ var batchId = data[id].batchId;
+ return byBatchId[batchId];
+ }
+ });
+ };
+ qq.status = {
+ SUBMITTING: "submitting",
+ SUBMITTED: "submitted",
+ REJECTED: "rejected",
+ QUEUED: "queued",
+ CANCELED: "canceled",
+ PAUSED: "paused",
+ UPLOADING: "uploading",
+ UPLOAD_RETRYING: "retrying upload",
+ UPLOAD_SUCCESSFUL: "upload successful",
+ UPLOAD_FAILED: "upload failed",
+ DELETE_FAILED: "delete failed",
+ DELETING: "deleting",
+ DELETED: "deleted"
+ };
+ (function() {
+ "use strict";
+ qq.basePublicApi = {
+ addBlobs: function(blobDataOrArray, params, endpoint) {
+ this.addFiles(blobDataOrArray, params, endpoint);
+ },
+ addInitialFiles: function(cannedFileList) {
+ var self = this;
+ qq.each(cannedFileList, function(index, cannedFile) {
+ self._addCannedFile(cannedFile);
+ });
+ },
+ addFiles: function(data, params, endpoint) {
+ this._maybeHandleIos8SafariWorkaround();
+ var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId, processBlob = qq.bind(function(blob) {
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName
+ }, batchId, verifiedFiles);
+ }, this), processBlobData = qq.bind(function(blobData) {
+ this._handleNewFile(blobData, batchId, verifiedFiles);
+ }, this), processCanvas = qq.bind(function(canvas) {
+ var blob = qq.canvasToBlob(canvas);
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName + ".png"
+ }, batchId, verifiedFiles);
+ }, this), processCanvasData = qq.bind(function(canvasData) {
+ var normalizedQuality = canvasData.quality && canvasData.quality / 100, blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);
+ this._handleNewFile({
+ blob: blob,
+ name: canvasData.name
+ }, batchId, verifiedFiles);
+ }, this), processFileOrInput = qq.bind(function(fileOrInput) {
+ if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {
+ var files = Array.prototype.slice.call(fileOrInput.files), self = this;
+ qq.each(files, function(idx, file) {
+ self._handleNewFile(file, batchId, verifiedFiles);
+ });
+ } else {
+ this._handleNewFile(fileOrInput, batchId, verifiedFiles);
+ }
+ }, this), normalizeData = function() {
+ if (qq.isFileList(data)) {
+ data = Array.prototype.slice.call(data);
+ }
+ data = [].concat(data);
+ }, self = this, verifiedFiles = [];
+ this._currentBatchId = batchId;
+ if (data) {
+ normalizeData();
+ qq.each(data, function(idx, fileContainer) {
+ if (qq.isFileOrInput(fileContainer)) {
+ processFileOrInput(fileContainer);
+ } else if (qq.isBlob(fileContainer)) {
+ processBlob(fileContainer);
+ } else if (qq.isObject(fileContainer)) {
+ if (fileContainer.blob && fileContainer.name) {
+ processBlobData(fileContainer);
+ } else if (fileContainer.canvas && fileContainer.name) {
+ processCanvasData(fileContainer);
+ }
+ } else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === "canvas") {
+ processCanvas(fileContainer);
+ } else {
+ self.log(fileContainer + " is not a valid file container! Ignoring!", "warn");
+ }
+ });
+ this.log("Received " + verifiedFiles.length + " files.");
+ this._prepareItemsForUpload(verifiedFiles, params, endpoint);
+ }
+ },
+ cancel: function(id) {
+ this._handler.cancel(id);
+ },
+ cancelAll: function() {
+ var storedIdsCopy = [], self = this;
+ qq.extend(storedIdsCopy, this._storedIds);
+ qq.each(storedIdsCopy, function(idx, storedFileId) {
+ self.cancel(storedFileId);
+ });
+ this._handler.cancelAll();
+ },
+ clearStoredFiles: function() {
+ this._storedIds = [];
+ },
+ continueUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (uploadData.status === qq.status.PAUSED) {
+ this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.", id, this.getName(id)));
+ this._uploadFile(id);
+ return true;
+ } else {
+ this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ deleteFile: function(id) {
+ return this._onSubmitDelete(id);
+ },
+ doesExist: function(fileOrBlobId) {
+ return this._handler.isValid(fileOrBlobId);
+ },
+ drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {
+ var promiseToReturn = new qq.Promise(), fileOrUrl, options;
+ if (this._imageGenerator) {
+ fileOrUrl = this._thumbnailUrls[fileId];
+ options = {
+ customResizeFunction: customResizeFunction,
+ maxSize: maxSize > 0 ? maxSize : null,
+ scale: maxSize > 0
+ };
+ if (!fromServer && qq.supportedFeatures.imagePreviews) {
+ fileOrUrl = this.getFile(fileId);
+ }
+ if (fileOrUrl == null) {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "File or URL not found."
+ });
+ } else {
+ this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(function success(modifiedContainer) {
+ promiseToReturn.success(modifiedContainer);
+ }, function failure(container, reason) {
+ promiseToReturn.failure({
+ container: container,
+ error: reason || "Problem generating thumbnail"
+ });
+ });
+ }
+ } else {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "Missing image generator module"
+ });
+ }
+ return promiseToReturn;
+ },
+ getButton: function(fileId) {
+ return this._getButton(this._buttonIdsForFileIds[fileId]);
+ },
+ getEndpoint: function(fileId) {
+ return this._endpointStore.get(fileId);
+ },
+ getFile: function(fileOrBlobId) {
+ return this._handler.getFile(fileOrBlobId) || null;
+ },
+ getInProgress: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED ]
+ }).length;
+ },
+ getName: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).name;
+ },
+ getParentId: function(id) {
+ var uploadDataEntry = this.getUploads({
+ id: id
+ }), parentId = null;
+ if (uploadDataEntry) {
+ if (uploadDataEntry.parentId !== undefined) {
+ parentId = uploadDataEntry.parentId;
+ }
+ }
+ return parentId;
+ },
+ getResumableFilesData: function() {
+ return this._handler.getResumableFilesData();
+ },
+ getSize: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).size;
+ },
+ getNetUploads: function() {
+ return this._netUploaded;
+ },
+ getRemainingAllowedItems: function() {
+ var allowedItems = this._currentItemLimit;
+ if (allowedItems > 0) {
+ return allowedItems - this._netUploadedOrQueued;
+ }
+ return null;
+ },
+ getUploads: function(optionalFilter) {
+ return this._uploadData.retrieve(optionalFilter);
+ },
+ getUuid: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).uuid;
+ },
+ log: function(str, level) {
+ if (this._options.debug && (!level || level === "info")) {
+ qq.log("[Fine Uploader " + qq.version + "] " + str);
+ } else if (level && level !== "info") {
+ qq.log("[Fine Uploader " + qq.version + "] " + str, level);
+ }
+ },
+ pauseUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (qq.indexOf([ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING ], uploadData.status) >= 0) {
+ if (this._handler.pause(id)) {
+ this._uploadData.setStatus(id, qq.status.PAUSED);
+ return true;
+ } else {
+ this.log(qq.format("Unable to pause file ID {} ({}).", id, this.getName(id)), "error");
+ }
+ } else {
+ this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ reset: function() {
+ this.log("Resetting uploader...");
+ this._handler.reset();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ this._paramsStore.reset();
+ this._endpointStore.reset();
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData.reset();
+ this._buttonIdsForFileIds = [];
+ this._pasteHandler && this._pasteHandler.reset();
+ this._options.session.refreshOnReset && this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._totalProgress && this._totalProgress.reset();
+ },
+ retry: function(id) {
+ return this._manualRetry(id);
+ },
+ scaleImage: function(id, specs) {
+ var self = this;
+ return qq.Scaler.prototype.scaleImage(id, specs, {
+ log: qq.bind(self.log, self),
+ getFile: qq.bind(self.getFile, self),
+ uploadData: self._uploadData
+ });
+ },
+ setCustomHeaders: function(headers, id) {
+ this._customHeadersStore.set(headers, id);
+ },
+ setDeleteFileCustomHeaders: function(headers, id) {
+ this._deleteFileCustomHeadersStore.set(headers, id);
+ },
+ setDeleteFileEndpoint: function(endpoint, id) {
+ this._deleteFileEndpointStore.set(endpoint, id);
+ },
+ setDeleteFileParams: function(params, id) {
+ this._deleteFileParamsStore.set(params, id);
+ },
+ setEndpoint: function(endpoint, id) {
+ this._endpointStore.set(endpoint, id);
+ },
+ setForm: function(elementOrId) {
+ this._updateFormSupportAndParams(elementOrId);
+ },
+ setItemLimit: function(newItemLimit) {
+ this._currentItemLimit = newItemLimit;
+ },
+ setName: function(id, newName) {
+ this._uploadData.updateName(id, newName);
+ },
+ setParams: function(params, id) {
+ this._paramsStore.set(params, id);
+ },
+ setUuid: function(id, newUuid) {
+ return this._uploadData.uuidChanged(id, newUuid);
+ },
+ uploadStoredFiles: function() {
+ if (this._storedIds.length === 0) {
+ this._itemError("noFilesError");
+ } else {
+ this._uploadStoredFiles();
+ }
+ }
+ };
+ qq.basePrivateApi = {
+ _addCannedFile: function(sessionData) {
+ var id = this._uploadData.addFile({
+ uuid: sessionData.uuid,
+ name: sessionData.name,
+ size: sessionData.size,
+ status: qq.status.UPLOAD_SUCCESSFUL
+ });
+ sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);
+ sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);
+ if (sessionData.thumbnailUrl) {
+ this._thumbnailUrls[id] = sessionData.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._netUploadedOrQueued++;
+ return id;
+ },
+ _annotateWithButtonId: function(file, associatedInput) {
+ if (qq.isFile(file)) {
+ file.qqButtonId = this._getButtonId(associatedInput);
+ }
+ },
+ _batchError: function(message) {
+ this._options.callbacks.onError(null, null, message, undefined);
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return new qq.DeleteFileAjaxRequester({
+ method: this._options.deleteFile.method.toUpperCase(),
+ maxConnections: this._options.maxConnections,
+ uuidParamName: this._options.request.uuidName,
+ customHeaders: this._deleteFileCustomHeadersStore,
+ paramsStore: this._deleteFileParamsStore,
+ endpointStore: this._deleteFileEndpointStore,
+ cors: this._options.cors,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ });
+ },
+ _createPasteHandler: function() {
+ var self = this;
+ return new qq.PasteSupport({
+ targetElement: this._options.paste.targetElement,
+ callbacks: {
+ log: qq.bind(self.log, self),
+ pasteReceived: function(blob) {
+ self._handleCheckedCallback({
+ name: "onPasteReceived",
+ callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),
+ onSuccess: qq.bind(self._handlePasteSuccess, self, blob),
+ identifier: "pasted image"
+ });
+ }
+ }
+ });
+ },
+ _createStore: function(initialValue, _readOnlyValues_) {
+ var store = {}, catchall = initialValue, perIdReadOnlyValues = {}, readOnlyValues = _readOnlyValues_, copy = function(orig) {
+ if (qq.isObject(orig)) {
+ return qq.extend({}, orig);
+ }
+ return orig;
+ }, getReadOnlyValues = function() {
+ if (qq.isFunction(readOnlyValues)) {
+ return readOnlyValues();
+ }
+ return readOnlyValues;
+ }, includeReadOnlyValues = function(id, existing) {
+ if (readOnlyValues && qq.isObject(existing)) {
+ qq.extend(existing, getReadOnlyValues());
+ }
+ if (perIdReadOnlyValues[id]) {
+ qq.extend(existing, perIdReadOnlyValues[id]);
+ }
+ };
+ return {
+ set: function(val, id) {
+ if (id == null) {
+ store = {};
+ catchall = copy(val);
+ } else {
+ store[id] = copy(val);
+ }
+ },
+ get: function(id) {
+ var values;
+ if (id != null && store[id]) {
+ values = store[id];
+ } else {
+ values = copy(catchall);
+ }
+ includeReadOnlyValues(id, values);
+ return copy(values);
+ },
+ addReadOnly: function(id, values) {
+ if (qq.isObject(store)) {
+ if (id === null) {
+ if (qq.isFunction(values)) {
+ readOnlyValues = values;
+ } else {
+ readOnlyValues = readOnlyValues || {};
+ qq.extend(readOnlyValues, values);
+ }
+ } else {
+ perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};
+ qq.extend(perIdReadOnlyValues[id], values);
+ }
+ }
+ },
+ remove: function(fileId) {
+ return delete store[fileId];
+ },
+ reset: function() {
+ store = {};
+ perIdReadOnlyValues = {};
+ catchall = initialValue;
+ }
+ };
+ },
+ _createUploadDataTracker: function() {
+ var self = this;
+ return new qq.UploadData({
+ getName: function(id) {
+ return self.getName(id);
+ },
+ getUuid: function(id) {
+ return self.getUuid(id);
+ },
+ getSize: function(id) {
+ return self.getSize(id);
+ },
+ onStatusChange: function(id, oldStatus, newStatus) {
+ self._onUploadStatusChange(id, oldStatus, newStatus);
+ self._options.callbacks.onStatusChange(id, oldStatus, newStatus);
+ self._maybeAllComplete(id, newStatus);
+ if (self._totalProgress) {
+ setTimeout(function() {
+ self._totalProgress.onStatusChange(id, oldStatus, newStatus);
+ }, 0);
+ }
+ }
+ });
+ },
+ _createUploadButton: function(spec) {
+ var self = this, acceptFiles = spec.accept || this._options.validation.acceptFiles, allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions, button;
+ function allowMultiple() {
+ if (qq.supportedFeatures.ajaxUploading) {
+ if (self._options.workarounds.iosEmptyVideos && qq.ios() && !qq.ios6() && self._isAllowedExtension(allowedExtensions, ".mov")) {
+ return false;
+ }
+ if (spec.multiple === undefined) {
+ return self._options.multiple;
+ }
+ return spec.multiple;
+ }
+ return false;
+ }
+ button = new qq.UploadButton({
+ acceptFiles: acceptFiles,
+ element: spec.element,
+ focusClass: this._options.classes.buttonFocus,
+ folders: spec.folders,
+ hoverClass: this._options.classes.buttonHover,
+ ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,
+ multiple: allowMultiple(),
+ name: this._options.request.inputName,
+ onChange: function(input) {
+ self._onInputChange(input);
+ },
+ title: spec.title == null ? this._options.text.fileInputTitle : spec.title
+ });
+ this._disposeSupport.addDisposer(function() {
+ button.dispose();
+ });
+ self._buttons.push(button);
+ return button;
+ },
+ _createUploadHandler: function(additionalOptions, namespace) {
+ var self = this, lastOnProgress = {}, options = {
+ debug: this._options.debug,
+ maxConnections: this._options.maxConnections,
+ cors: this._options.cors,
+ paramsStore: this._paramsStore,
+ endpointStore: this._endpointStore,
+ chunking: this._options.chunking,
+ resume: this._options.resume,
+ blobs: this._options.blobs,
+ log: qq.bind(self.log, self),
+ preventRetryParam: this._options.retry.preventRetryResponseProperty,
+ onProgress: function(id, name, loaded, total) {
+ if (loaded < 0 || total < 0) {
+ return;
+ }
+ if (lastOnProgress[id]) {
+ if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ } else {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ lastOnProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onComplete: function(id, name, result, xhr) {
+ delete lastOnProgress[id];
+ var status = self.getUploads({
+ id: id
+ }).status, retVal;
+ if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {
+ return;
+ }
+ retVal = self._onComplete(id, name, result, xhr);
+ if (retVal instanceof qq.Promise) {
+ retVal.done(function() {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ });
+ } else {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ }
+ },
+ onCancel: function(id, name, cancelFinalizationEffort) {
+ var promise = new qq.Promise();
+ self._handleCheckedCallback({
+ name: "onCancel",
+ callback: qq.bind(self._options.callbacks.onCancel, self, id, name),
+ onFailure: promise.failure,
+ onSuccess: function() {
+ cancelFinalizationEffort.then(function() {
+ self._onCancel(id, name);
+ });
+ promise.success();
+ },
+ identifier: id
+ });
+ return promise;
+ },
+ onUploadPrep: qq.bind(this._onUploadPrep, this),
+ onUpload: function(id, name) {
+ self._onUpload(id, name);
+ self._options.callbacks.onUpload(id, name);
+ },
+ onUploadChunk: function(id, name, chunkData) {
+ self._onUploadChunk(id, chunkData);
+ self._options.callbacks.onUploadChunk(id, name, chunkData);
+ },
+ onUploadChunkSuccess: function(id, chunkData, result, xhr) {
+ self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);
+ },
+ onResume: function(id, name, chunkData) {
+ return self._options.callbacks.onResume(id, name, chunkData);
+ },
+ onAutoRetry: function(id, name, responseJSON, xhr) {
+ return self._onAutoRetry.apply(self, arguments);
+ },
+ onUuidChanged: function(id, newUuid) {
+ self.log("Server requested UUID change from '" + self.getUuid(id) + "' to '" + newUuid + "'");
+ self.setUuid(id, newUuid);
+ },
+ getName: qq.bind(self.getName, self),
+ getUuid: qq.bind(self.getUuid, self),
+ getSize: qq.bind(self.getSize, self),
+ setSize: qq.bind(self._setSize, self),
+ getDataByUuid: function(uuid) {
+ return self.getUploads({
+ uuid: uuid
+ });
+ },
+ isQueued: function(id) {
+ var status = self.getUploads({
+ id: id
+ }).status;
+ return status === qq.status.QUEUED || status === qq.status.SUBMITTED || status === qq.status.UPLOAD_RETRYING || status === qq.status.PAUSED;
+ },
+ getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,
+ getIdsInBatch: self._uploadData.getIdsInBatch
+ };
+ qq.each(this._options.request, function(prop, val) {
+ options[prop] = val;
+ });
+ options.customHeaders = this._customHeadersStore;
+ if (additionalOptions) {
+ qq.each(additionalOptions, function(key, val) {
+ options[key] = val;
+ });
+ }
+ return new qq.UploadHandlerController(options, namespace);
+ },
+ _fileOrBlobRejected: function(id) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.REJECTED);
+ },
+ _formatSize: function(bytes) {
+ if (bytes === 0) {
+ return bytes + this._options.text.sizeSymbols[0];
+ }
+ var i = -1;
+ do {
+ bytes = bytes / 1e3;
+ i++;
+ } while (bytes > 999);
+ return Math.max(bytes, .1).toFixed(1) + this._options.text.sizeSymbols[i];
+ },
+ _generateExtraButtonSpecs: function() {
+ var self = this;
+ this._extraButtonSpecs = {};
+ qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {
+ var multiple = extraButtonOptionEntry.multiple, validation = qq.extend({}, self._options.validation, true), extraButtonSpec = qq.extend({}, extraButtonOptionEntry);
+ if (multiple === undefined) {
+ multiple = self._options.multiple;
+ }
+ if (extraButtonSpec.validation) {
+ qq.extend(validation, extraButtonOptionEntry.validation, true);
+ }
+ qq.extend(extraButtonSpec, {
+ multiple: multiple,
+ validation: validation
+ }, true);
+ self._initExtraButton(extraButtonSpec);
+ });
+ },
+ _getButton: function(buttonId) {
+ var extraButtonsSpec = this._extraButtonSpecs[buttonId];
+ if (extraButtonsSpec) {
+ return extraButtonsSpec.element;
+ } else if (buttonId === this._defaultButtonId) {
+ return this._options.button;
+ }
+ },
+ _getButtonId: function(buttonOrFileInputOrFile) {
+ var inputs, fileInput, fileBlobOrInput = buttonOrFileInputOrFile;
+ if (fileBlobOrInput instanceof qq.BlobProxy) {
+ fileBlobOrInput = fileBlobOrInput.referenceBlob;
+ }
+ if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {
+ if (qq.isFile(fileBlobOrInput)) {
+ return fileBlobOrInput.qqButtonId;
+ } else if (fileBlobOrInput.tagName.toLowerCase() === "input" && fileBlobOrInput.type.toLowerCase() === "file") {
+ return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ inputs = fileBlobOrInput.getElementsByTagName("input");
+ qq.each(inputs, function(idx, input) {
+ if (input.getAttribute("type") === "file") {
+ fileInput = input;
+ return false;
+ }
+ });
+ if (fileInput) {
+ return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ }
+ },
+ _getNotFinished: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED, qq.status.SUBMITTING, qq.status.SUBMITTED, qq.status.PAUSED ]
+ }).length;
+ },
+ _getValidationBase: function(buttonId) {
+ var extraButtonSpec = this._extraButtonSpecs[buttonId];
+ return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;
+ },
+ _getValidationDescriptor: function(fileWrapper) {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return {
+ name: qq.getFilename(fileWrapper.file.referenceBlob),
+ size: fileWrapper.file.referenceBlob.size
+ };
+ }
+ return {
+ name: this.getUploads({
+ id: fileWrapper.id
+ }).name,
+ size: this.getUploads({
+ id: fileWrapper.id
+ }).size
+ };
+ },
+ _getValidationDescriptors: function(fileWrappers) {
+ var self = this, fileDescriptors = [];
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ fileDescriptors.push(self._getValidationDescriptor(fileWrapper));
+ });
+ return fileDescriptors;
+ },
+ _handleCameraAccess: function() {
+ if (this._options.camera.ios && qq.ios()) {
+ var acceptIosCamera = "image/*;capture=camera", button = this._options.camera.button, buttonId = button ? this._getButtonId(button) : this._defaultButtonId, optionRoot = this._options;
+ if (buttonId && buttonId !== this._defaultButtonId) {
+ optionRoot = this._extraButtonSpecs[buttonId];
+ }
+ optionRoot.multiple = false;
+ if (optionRoot.validation.acceptFiles === null) {
+ optionRoot.validation.acceptFiles = acceptIosCamera;
+ } else {
+ optionRoot.validation.acceptFiles += "," + acceptIosCamera;
+ }
+ qq.each(this._buttons, function(idx, button) {
+ if (button.getButtonId() === buttonId) {
+ button.setMultiple(optionRoot.multiple);
+ button.setAcceptFiles(optionRoot.acceptFiles);
+ return false;
+ }
+ });
+ }
+ },
+ _handleCheckedCallback: function(details) {
+ var self = this, callbackRetVal = details.callback();
+ if (qq.isGenericPromise(callbackRetVal)) {
+ this.log(details.name + " - waiting for " + details.name + " promise to be fulfilled for " + details.identifier);
+ return callbackRetVal.then(function(successParam) {
+ self.log(details.name + " promise success for " + details.identifier);
+ details.onSuccess(successParam);
+ }, function() {
+ if (details.onFailure) {
+ self.log(details.name + " promise failure for " + details.identifier);
+ details.onFailure();
+ } else {
+ self.log(details.name + " promise failure for " + details.identifier);
+ }
+ });
+ }
+ if (callbackRetVal !== false) {
+ details.onSuccess(callbackRetVal);
+ } else {
+ if (details.onFailure) {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Invoking failure callback.");
+ details.onFailure();
+ } else {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Will not proceed.");
+ }
+ }
+ return callbackRetVal;
+ },
+ _handleNewFile: function(file, batchId, newFileWrapperList) {
+ var self = this, uuid = qq.getUniqueId(), size = -1, name = qq.getFilename(file), actualFile = file.blob || file, handler = this._customNewFileHandler ? this._customNewFileHandler : qq.bind(self._handleNewFileGeneric, self);
+ if (!qq.isInput(actualFile) && actualFile.size >= 0) {
+ size = actualFile.size;
+ }
+ handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {
+ uploadData: self._uploadData,
+ paramsStore: self._paramsStore,
+ addFileToHandler: function(id, file) {
+ self._handler.add(id, file);
+ self._netUploadedOrQueued++;
+ self._trackButton(id);
+ }
+ });
+ },
+ _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {
+ var id = this._uploadData.addFile({
+ uuid: uuid,
+ name: name,
+ size: size,
+ batchId: batchId
+ });
+ this._handler.add(id, file);
+ this._trackButton(id);
+ this._netUploadedOrQueued++;
+ fileList.push({
+ id: id,
+ file: file
+ });
+ },
+ _handlePasteSuccess: function(blob, extSuppliedName) {
+ var extension = blob.type.split("/")[1], name = extSuppliedName;
+ if (name == null) {
+ name = this._options.paste.defaultName;
+ }
+ name += "." + extension;
+ this.addFiles({
+ name: name,
+ blob: blob
+ });
+ },
+ _initExtraButton: function(spec) {
+ var button = this._createUploadButton({
+ accept: spec.validation.acceptFiles,
+ allowedExtensions: spec.validation.allowedExtensions,
+ element: spec.element,
+ folders: spec.folders,
+ multiple: spec.multiple,
+ title: spec.fileInputTitle
+ });
+ this._extraButtonSpecs[button.getButtonId()] = spec;
+ },
+ _initFormSupportAndParams: function() {
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore = this._createStore(this._options.request.params, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this._options.request.endpoint = this._formSupport.newEndpoint;
+ }
+ } else {
+ this._paramsStore = this._createStore(this._options.request.params);
+ }
+ },
+ _isDeletePossible: function() {
+ if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {
+ return false;
+ }
+ if (this._options.cors.expected) {
+ if (qq.supportedFeatures.deleteFileCorsXhr) {
+ return true;
+ }
+ if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ },
+ _isAllowedExtension: function(allowed, fileName) {
+ var valid = false;
+ if (!allowed.length) {
+ return true;
+ }
+ qq.each(allowed, function(idx, allowedExt) {
+ if (qq.isString(allowedExt)) {
+ var extRegex = new RegExp("\\." + allowedExt + "$", "i");
+ if (fileName.match(extRegex) != null) {
+ valid = true;
+ return false;
+ }
+ }
+ });
+ return valid;
+ },
+ _itemError: function(code, maybeNameOrNames, item) {
+ var message = this._options.messages[code], allowedExtensions = [], names = [].concat(maybeNameOrNames), name = names[0], buttonId = this._getButtonId(item), validationBase = this._getValidationBase(buttonId), extensionsForMessage, placeholderMatch;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {
+ if (qq.isString(allowedExtension)) {
+ allowedExtensions.push(allowedExtension);
+ }
+ });
+ extensionsForMessage = allowedExtensions.join(", ").toLowerCase();
+ r("{file}", this._options.formatFileName(name));
+ r("{extensions}", extensionsForMessage);
+ r("{sizeLimit}", this._formatSize(validationBase.sizeLimit));
+ r("{minSizeLimit}", this._formatSize(validationBase.minSizeLimit));
+ placeholderMatch = message.match(/(\{\w+\})/g);
+ if (placeholderMatch !== null) {
+ qq.each(placeholderMatch, function(idx, placeholder) {
+ r(placeholder, names[idx]);
+ });
+ }
+ this._options.callbacks.onError(null, name, message, undefined);
+ return message;
+ },
+ _manualRetry: function(id, callback) {
+ if (this._onBeforeManualRetry(id)) {
+ this._netUploadedOrQueued++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ if (callback) {
+ callback(id);
+ } else {
+ this._handler.retry(id);
+ }
+ return true;
+ }
+ },
+ _maybeAllComplete: function(id, status) {
+ var self = this, notFinished = this._getNotFinished();
+ if (status === qq.status.UPLOAD_SUCCESSFUL) {
+ this._succeededSinceLastAllComplete.push(id);
+ } else if (status === qq.status.UPLOAD_FAILED) {
+ this._failedSinceLastAllComplete.push(id);
+ }
+ if (notFinished === 0 && (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {
+ setTimeout(function() {
+ self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);
+ }, 0);
+ }
+ },
+ _maybeHandleIos8SafariWorkaround: function() {
+ var self = this;
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ setTimeout(function() {
+ window.alert(self._options.messages.unsupportedBrowserIos8Safari);
+ }, 0);
+ throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);
+ }
+ },
+ _maybeParseAndSendUploadError: function(id, name, response, xhr) {
+ if (!response.success) {
+ if (xhr && xhr.status !== 200 && !response.error) {
+ this._options.callbacks.onError(id, name, "XHR returned response code " + xhr.status, xhr);
+ } else {
+ var errorReason = response.error ? response.error : this._options.text.defaultResponseError;
+ this._options.callbacks.onError(id, name, errorReason, xhr);
+ }
+ }
+ },
+ _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {
+ var self = this;
+ if (items.length > index) {
+ if (validItem || !this._options.validation.stopOnFirstInvalidFile) {
+ setTimeout(function() {
+ var validationDescriptor = self._getValidationDescriptor(items[index]), buttonId = self._getButtonId(items[index].file), button = self._getButton(buttonId);
+ self._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),
+ onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),
+ onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),
+ identifier: "Item '" + validationDescriptor.name + "', size: " + validationDescriptor.size
+ });
+ }, 0);
+ } else if (!validItem) {
+ for (;index < items.length; index++) {
+ self._fileOrBlobRejected(items[index].id);
+ }
+ }
+ }
+ },
+ _onAllComplete: function(successful, failed) {
+ this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);
+ this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ },
+ _onAutoRetry: function(id, name, responseJSON, xhr, callback) {
+ var self = this;
+ self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];
+ if (self._shouldAutoRetry(id, name, responseJSON)) {
+ var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1e3;
+ self._maybeParseAndSendUploadError.apply(self, arguments);
+ self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);
+ self._onBeforeAutoRetry(id, name);
+ self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ self._retryTimeouts[id] = setTimeout(function() {
+ self.log("Starting retry for " + name + "...");
+ if (callback) {
+ callback(id);
+ } else {
+ self._handler.retry(id);
+ }
+ }, retryWaitPeriod);
+ return true;
+ }
+ },
+ _onBeforeAutoRetry: function(id, name) {
+ this.log("Waiting " + this._options.retry.autoAttemptDelay + " seconds before retrying " + name + "...");
+ },
+ _onBeforeManualRetry: function(id) {
+ var itemLimit = this._currentItemLimit, fileName;
+ if (this._preventRetries[id]) {
+ this.log("Retries are forbidden for id " + id, "warn");
+ return false;
+ } else if (this._handler.isValid(id)) {
+ fileName = this.getName(id);
+ if (this._options.callbacks.onManualRetry(id, fileName) === false) {
+ return false;
+ }
+ if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {
+ this._itemError("retryFailTooManyItems");
+ return false;
+ }
+ this.log("Retrying upload for '" + fileName + "' (id: " + id + ")...");
+ return true;
+ } else {
+ this.log("'" + id + "' is not a valid file ID", "error");
+ return false;
+ }
+ },
+ _onCancel: function(id, name) {
+ this._netUploadedOrQueued--;
+ clearTimeout(this._retryTimeouts[id]);
+ var storedItemIndex = qq.indexOf(this._storedIds, id);
+ if (!this._options.autoUpload && storedItemIndex >= 0) {
+ this._storedIds.splice(storedItemIndex, 1);
+ }
+ this._uploadData.setStatus(id, qq.status.CANCELED);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ if (!result.success) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);
+ if (result[this._options.retry.preventRetryResponseProperty] === true) {
+ this._preventRetries[id] = true;
+ }
+ } else {
+ if (result.thumbnailUrl) {
+ this._thumbnailUrls[id] = result.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);
+ }
+ this._maybeParseAndSendUploadError(id, name, result, xhr);
+ return result.success ? true : false;
+ },
+ _onDelete: function(id) {
+ this._uploadData.setStatus(id, qq.status.DELETING);
+ },
+ _onDeleteComplete: function(id, xhrOrXdr, isError) {
+ var name = this.getName(id);
+ if (isError) {
+ this._uploadData.setStatus(id, qq.status.DELETE_FAILED);
+ this.log("Delete request for '" + name + "' has failed.", "error");
+ if (xhrOrXdr.withCredentials === undefined) {
+ this._options.callbacks.onError(id, name, "Delete request failed", xhrOrXdr);
+ } else {
+ this._options.callbacks.onError(id, name, "Delete request failed with response code " + xhrOrXdr.status, xhrOrXdr);
+ }
+ } else {
+ this._netUploadedOrQueued--;
+ this._netUploaded--;
+ this._handler.expunge(id);
+ this._uploadData.setStatus(id, qq.status.DELETED);
+ this.log("Delete request for '" + name + "' has succeeded.");
+ }
+ },
+ _onInputChange: function(input) {
+ var fileIndex;
+ if (qq.supportedFeatures.ajaxUploading) {
+ for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {
+ this._annotateWithButtonId(input.files[fileIndex], input);
+ }
+ this.addFiles(input.files);
+ } else if (input.value.length > 0) {
+ this.addFiles(input);
+ }
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);
+ },
+ _onSubmit: function(id, name) {},
+ _onSubmitCallbackSuccess: function(id, name) {
+ this._onSubmit.apply(this, arguments);
+ this._uploadData.setStatus(id, qq.status.SUBMITTED);
+ this._onSubmitted.apply(this, arguments);
+ if (this._options.autoUpload) {
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ this._uploadFile(id);
+ } else {
+ this._storeForLater(id);
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ }
+ },
+ _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {
+ var uuid = this.getUuid(id), adjustedOnSuccessCallback;
+ if (onSuccessCallback) {
+ adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);
+ }
+ if (this._isDeletePossible()) {
+ this._handleCheckedCallback({
+ name: "onSubmitDelete",
+ callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),
+ onSuccess: adjustedOnSuccessCallback || qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),
+ identifier: id
+ });
+ return true;
+ } else {
+ this.log("Delete request ignored for ID " + id + ", delete feature is disabled or request not possible " + "due to CORS on a user agent that does not support pre-flighting.", "warn");
+ return false;
+ }
+ },
+ _onSubmitted: function(id) {},
+ _onTotalProgress: function(loaded, total) {
+ this._options.callbacks.onTotalProgress(loaded, total);
+ },
+ _onUploadPrep: function(id) {},
+ _onUpload: function(id, name) {
+ this._uploadData.setStatus(id, qq.status.UPLOADING);
+ },
+ _onUploadChunk: function(id, chunkData) {},
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.PAUSED) {
+ clearTimeout(this._retryTimeouts[id]);
+ }
+ },
+ _onValidateBatchCallbackFailure: function(fileWrappers) {
+ var self = this;
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ self._fileOrBlobRejected(fileWrapper.id);
+ });
+ },
+ _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {
+ var errorMessage, itemLimit = this._currentItemLimit, proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;
+ if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {
+ if (items.length > 0) {
+ this._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),
+ onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),
+ onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),
+ identifier: "Item '" + items[0].file.name + "', size: " + items[0].file.size
+ });
+ } else {
+ this._itemError("noFilesError");
+ }
+ } else {
+ this._onValidateBatchCallbackFailure(items);
+ errorMessage = this._options.messages.tooManyItemsError.replace(/\{netItems\}/g, proposedNetFilesUploadedOrQueued).replace(/\{itemLimit\}/g, itemLimit);
+ this._batchError(errorMessage);
+ }
+ },
+ _onValidateCallbackFailure: function(items, index, params, endpoint) {
+ var nextIndex = index + 1;
+ this._fileOrBlobRejected(items[index].id, items[index].file.name);
+ this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ },
+ _onValidateCallbackSuccess: function(items, index, params, endpoint) {
+ var self = this, nextIndex = index + 1, validationDescriptor = this._getValidationDescriptor(items[index]);
+ this._validateFileOrBlobData(items[index], validationDescriptor).then(function() {
+ self._upload(items[index].id, params, endpoint);
+ self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);
+ }, function() {
+ self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ });
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ if (items.length === 0) {
+ this._itemError("noFilesError");
+ return;
+ }
+ var validationDescriptors = this._getValidationDescriptors(items), buttonId = this._getButtonId(items[0].file), button = this._getButton(buttonId);
+ this._handleCheckedCallback({
+ name: "onValidateBatch",
+ callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),
+ onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),
+ onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),
+ identifier: "batch validation"
+ });
+ },
+ _preventLeaveInProgress: function() {
+ var self = this;
+ this._disposeSupport.attach(window, "beforeunload", function(e) {
+ if (self.getInProgress()) {
+ e = e || window.event;
+ e.returnValue = self._options.messages.onLeave;
+ return self._options.messages.onLeave;
+ }
+ });
+ },
+ _refreshSessionData: function() {
+ var self = this, options = this._options.session;
+ if (qq.Session && this._options.session.endpoint != null) {
+ if (!this._session) {
+ qq.extend(options, {
+ cors: this._options.cors
+ });
+ options.log = qq.bind(this.log, this);
+ options.addFileRecord = qq.bind(this._addCannedFile, this);
+ this._session = new qq.Session(options);
+ }
+ setTimeout(function() {
+ self._session.refresh().then(function(response, xhrOrXdr) {
+ self._sessionRequestComplete();
+ self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);
+ }, function(response, xhrOrXdr) {
+ self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);
+ });
+ }, 0);
+ }
+ },
+ _sessionRequestComplete: function() {},
+ _setSize: function(id, newSize) {
+ this._uploadData.updateSize(id, newSize);
+ this._totalProgress && this._totalProgress.onNewSize(id);
+ },
+ _shouldAutoRetry: function(id, name, responseJSON) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!this._preventRetries[id] && this._options.retry.enableAuto && uploadData.status !== qq.status.PAUSED) {
+ if (this._autoRetries[id] === undefined) {
+ this._autoRetries[id] = 0;
+ }
+ if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {
+ this._autoRetries[id] += 1;
+ return true;
+ }
+ }
+ return false;
+ },
+ _storeForLater: function(id) {
+ this._storedIds.push(id);
+ },
+ _trackButton: function(id) {
+ var buttonId;
+ if (qq.supportedFeatures.ajaxUploading) {
+ buttonId = this._handler.getFile(id).qqButtonId;
+ } else {
+ buttonId = this._getButtonId(this._handler.getInput(id));
+ }
+ if (buttonId) {
+ this._buttonIdsForFileIds[id] = buttonId;
+ }
+ },
+ _updateFormSupportAndParams: function(formElementOrId) {
+ this._options.form.element = formElementOrId;
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this.setEndpoint(this._formSupport.newEndpoint);
+ }
+ }
+ },
+ _upload: function(id, params, endpoint) {
+ var name = this.getName(id);
+ if (params) {
+ this.setParams(params, id);
+ }
+ if (endpoint) {
+ this.setEndpoint(endpoint, id);
+ }
+ this._handleCheckedCallback({
+ name: "onSubmit",
+ callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),
+ onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),
+ onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),
+ identifier: id
+ });
+ },
+ _uploadFile: function(id) {
+ if (!this._handler.upload(id)) {
+ this._uploadData.setStatus(id, qq.status.QUEUED);
+ }
+ },
+ _uploadStoredFiles: function() {
+ var idToUpload, stillSubmitting, self = this;
+ while (this._storedIds.length) {
+ idToUpload = this._storedIds.shift();
+ this._uploadFile(idToUpload);
+ }
+ stillSubmitting = this.getUploads({
+ status: qq.status.SUBMITTING
+ }).length;
+ if (stillSubmitting) {
+ qq.log("Still waiting for " + stillSubmitting + " files to clear submit queue. Will re-parse stored IDs array shortly.");
+ setTimeout(function() {
+ self._uploadStoredFiles();
+ }, 1e3);
+ }
+ },
+ _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {
+ var self = this, file = function() {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return fileWrapper.file.referenceBlob;
+ }
+ return fileWrapper.file;
+ }(), name = validationDescriptor.name, size = validationDescriptor.size, buttonId = this._getButtonId(fileWrapper.file), validationBase = this._getValidationBase(buttonId), validityChecker = new qq.Promise();
+ validityChecker.then(function() {}, function() {
+ self._fileOrBlobRejected(fileWrapper.id, name);
+ });
+ if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {
+ this._itemError("typeError", name, file);
+ return validityChecker.failure();
+ }
+ if (!this._options.validation.allowEmpty && size === 0) {
+ this._itemError("emptyError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {
+ this._itemError("sizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && size < validationBase.minSizeLimit) {
+ this._itemError("minSizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {
+ new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(validityChecker.success, function(errorCode) {
+ self._itemError(errorCode + "ImageError", name, file);
+ validityChecker.failure();
+ });
+ } else {
+ validityChecker.success();
+ }
+ return validityChecker;
+ },
+ _wrapCallbacks: function() {
+ var self, safeCallback, prop;
+ self = this;
+ safeCallback = function(name, callback, args) {
+ var errorMsg;
+ try {
+ return callback.apply(self, args);
+ } catch (exception) {
+ errorMsg = exception.message || exception.toString();
+ self.log("Caught exception in '" + name + "' callback - " + errorMsg, "error");
+ }
+ };
+ for (prop in this._options.callbacks) {
+ (function() {
+ var callbackName, callbackFunc;
+ callbackName = prop;
+ callbackFunc = self._options.callbacks[callbackName];
+ self._options.callbacks[callbackName] = function() {
+ return safeCallback(callbackName, callbackFunc, arguments);
+ };
+ })();
+ }
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.FineUploaderBasic = function(o) {
+ var self = this;
+ this._options = {
+ debug: false,
+ button: null,
+ multiple: true,
+ maxConnections: 3,
+ disableCancelForFormUploads: false,
+ autoUpload: true,
+ request: {
+ customHeaders: {},
+ endpoint: "/server/upload",
+ filenameParam: "qqfilename",
+ forceMultipart: true,
+ inputName: "qqfile",
+ method: "POST",
+ params: {},
+ paramsInBody: true,
+ totalFileSizeName: "qqtotalfilesize",
+ uuidName: "qquuid"
+ },
+ validation: {
+ allowedExtensions: [],
+ sizeLimit: 0,
+ minSizeLimit: 0,
+ itemLimit: 0,
+ stopOnFirstInvalidFile: true,
+ acceptFiles: null,
+ image: {
+ maxHeight: 0,
+ maxWidth: 0,
+ minHeight: 0,
+ minWidth: 0
+ },
+ allowEmpty: false
+ },
+ callbacks: {
+ onSubmit: function(id, name) {},
+ onSubmitted: function(id, name) {},
+ onComplete: function(id, name, responseJSON, maybeXhr) {},
+ onAllComplete: function(successful, failed) {},
+ onCancel: function(id, name) {},
+ onUpload: function(id, name) {},
+ onUploadChunk: function(id, name, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onProgress: function(id, name, loaded, total) {},
+ onTotalProgress: function(loaded, total) {},
+ onError: function(id, name, reason, maybeXhrOrXdr) {},
+ onAutoRetry: function(id, name, attemptNumber) {},
+ onManualRetry: function(id, name) {},
+ onValidateBatch: function(fileOrBlobData) {},
+ onValidate: function(fileOrBlobData) {},
+ onSubmitDelete: function(id) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {},
+ onPasteReceived: function(blob) {},
+ onStatusChange: function(id, oldStatus, newStatus) {},
+ onSessionRequestComplete: function(response, success, xhrOrXdr) {}
+ },
+ messages: {
+ typeError: "{file} has an invalid extension. Valid extension(s): {extensions}.",
+ sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
+ minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
+ emptyError: "{file} is empty, please select files again without it.",
+ noFilesError: "No files to upload.",
+ tooManyItemsError: "Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.",
+ maxHeightImageError: "Image is too tall.",
+ maxWidthImageError: "Image is too wide.",
+ minHeightImageError: "Image is not tall enough.",
+ minWidthImageError: "Image is not wide enough.",
+ retryFailTooManyItems: "Retry failed - you have reached your file limit.",
+ onLeave: "The files are being uploaded, if you leave now the upload will be canceled.",
+ unsupportedBrowserIos8Safari: "Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues."
+ },
+ retry: {
+ enableAuto: false,
+ maxAutoAttempts: 3,
+ autoAttemptDelay: 5,
+ preventRetryResponseProperty: "preventRetry"
+ },
+ classes: {
+ buttonHover: "qq-upload-button-hover",
+ buttonFocus: "qq-upload-button-focus"
+ },
+ chunking: {
+ enabled: false,
+ concurrent: {
+ enabled: false
+ },
+ mandatory: false,
+ paramNames: {
+ partIndex: "qqpartindex",
+ partByteOffset: "qqpartbyteoffset",
+ chunkSize: "qqchunksize",
+ totalFileSize: "qqtotalfilesize",
+ totalParts: "qqtotalparts"
+ },
+ partSize: 2e6,
+ success: {
+ endpoint: null
+ }
+ },
+ resume: {
+ enabled: false,
+ recordsExpireIn: 7,
+ paramNames: {
+ resuming: "qqresume"
+ }
+ },
+ formatFileName: function(fileOrBlobName) {
+ return fileOrBlobName;
+ },
+ text: {
+ defaultResponseError: "Upload failure reason unknown",
+ fileInputTitle: "file input",
+ sizeSymbols: [ "kB", "MB", "GB", "TB", "PB", "EB" ]
+ },
+ deleteFile: {
+ enabled: false,
+ method: "DELETE",
+ endpoint: "/server/upload",
+ customHeaders: {},
+ params: {}
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false,
+ allowXdr: false
+ },
+ blobs: {
+ defaultName: "misc_data"
+ },
+ paste: {
+ targetElement: null,
+ defaultName: "pasted_image"
+ },
+ camera: {
+ ios: false,
+ button: null
+ },
+ extraButtons: [],
+ session: {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ refreshOnReset: true
+ },
+ form: {
+ element: "qq-form",
+ autoUpload: false,
+ interceptSubmit: true
+ },
+ scaling: {
+ customResizer: null,
+ sendOriginal: true,
+ orient: true,
+ defaultType: null,
+ defaultQuality: 80,
+ failureText: "Failed to scale",
+ includeExif: false,
+ sizes: []
+ },
+ workarounds: {
+ iosEmptyVideos: true,
+ ios8SafariUploads: true,
+ ios8BrowserCrash: false
+ }
+ };
+ qq.extend(this._options, o, true);
+ this._buttons = [];
+ this._extraButtonSpecs = {};
+ this._buttonIdsForFileIds = [];
+ this._wrapCallbacks();
+ this._disposeSupport = new qq.DisposeSupport();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData = this._createUploadDataTracker();
+ this._initFormSupportAndParams();
+ this._customHeadersStore = this._createStore(this._options.request.customHeaders);
+ this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);
+ this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);
+ this._endpointStore = this._createStore(this._options.request.endpoint);
+ this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);
+ this._handler = this._createUploadHandler();
+ this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();
+ if (this._options.button) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._options.button,
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._generateExtraButtonSpecs();
+ this._handleCameraAccess();
+ if (this._options.paste.targetElement) {
+ if (qq.PasteSupport) {
+ this._pasteHandler = this._createPasteHandler();
+ } else {
+ this.log("Paste support module not found", "error");
+ }
+ }
+ this._preventLeaveInProgress();
+ this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));
+ this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._scaler = qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this)) || {};
+ if (this._scaler.enabled) {
+ this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);
+ }
+ if (qq.TotalProgress && qq.supportedFeatures.progressBar) {
+ this._totalProgress = new qq.TotalProgress(qq.bind(this._onTotalProgress, this), function(id) {
+ var entry = self._uploadData.retrieve({
+ id: id
+ });
+ return entry && entry.size || 0;
+ });
+ }
+ this._currentItemLimit = this._options.validation.itemLimit;
+ };
+ qq.FineUploaderBasic.prototype = qq.basePublicApi;
+ qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);
+ })();
+ qq.AjaxRequester = function(o) {
+ "use strict";
+ var log, shouldParamsBeInQueryString, queue = [], requestData = {}, options = {
+ acceptHeader: null,
+ validMethods: [ "PATCH", "POST", "PUT" ],
+ method: "POST",
+ contentType: "application/x-www-form-urlencoded",
+ maxConnections: 3,
+ customHeaders: {},
+ endpointStore: {},
+ paramsStore: {},
+ mandatedParams: {},
+ allowXRequestedWithAndCacheControl: true,
+ successfulResponseCodes: {
+ DELETE: [ 200, 202, 204 ],
+ PATCH: [ 200, 201, 202, 203, 204 ],
+ POST: [ 200, 201, 202, 203, 204 ],
+ PUT: [ 200, 201, 202, 203, 204 ],
+ GET: [ 200 ]
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onSend: function(id) {},
+ onComplete: function(id, xhrOrXdr, isError) {},
+ onProgress: null
+ };
+ qq.extend(options, o);
+ log = options.log;
+ if (qq.indexOf(options.validMethods, options.method) < 0) {
+ throw new Error("'" + options.method + "' is not a supported method for this type of request!");
+ }
+ function isSimpleMethod() {
+ return qq.indexOf([ "GET", "POST", "HEAD" ], options.method) >= 0;
+ }
+ function containsNonSimpleHeaders(headers) {
+ var containsNonSimple = false;
+ qq.each(containsNonSimple, function(idx, header) {
+ if (qq.indexOf([ "Accept", "Accept-Language", "Content-Language", "Content-Type" ], header) < 0) {
+ containsNonSimple = true;
+ return false;
+ }
+ });
+ return containsNonSimple;
+ }
+ function isXdr(xhr) {
+ return options.cors.expected && xhr.withCredentials === undefined;
+ }
+ function getCorsAjaxTransport() {
+ var xhrOrXdr;
+ if (window.XMLHttpRequest || window.ActiveXObject) {
+ xhrOrXdr = qq.createXhrInstance();
+ if (xhrOrXdr.withCredentials === undefined) {
+ xhrOrXdr = new XDomainRequest();
+ xhrOrXdr.onload = function() {};
+ xhrOrXdr.onerror = function() {};
+ xhrOrXdr.ontimeout = function() {};
+ xhrOrXdr.onprogress = function() {};
+ }
+ }
+ return xhrOrXdr;
+ }
+ function getXhrOrXdr(id, suppliedXhr) {
+ var xhrOrXdr = requestData[id].xhr;
+ if (!xhrOrXdr) {
+ if (suppliedXhr) {
+ xhrOrXdr = suppliedXhr;
+ } else {
+ if (options.cors.expected) {
+ xhrOrXdr = getCorsAjaxTransport();
+ } else {
+ xhrOrXdr = qq.createXhrInstance();
+ }
+ }
+ requestData[id].xhr = xhrOrXdr;
+ }
+ return xhrOrXdr;
+ }
+ function dequeue(id) {
+ var i = qq.indexOf(queue, id), max = options.maxConnections, nextId;
+ delete requestData[id];
+ queue.splice(i, 1);
+ if (queue.length >= max && i < max) {
+ nextId = queue[max - 1];
+ sendRequest(nextId);
+ }
+ }
+ function onComplete(id, xdrError) {
+ var xhr = getXhrOrXdr(id), method = options.method, isError = xdrError === true;
+ dequeue(id);
+ if (isError) {
+ log(method + " request for " + id + " has failed", "error");
+ } else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {
+ isError = true;
+ log(method + " request for " + id + " has failed - response code " + xhr.status, "error");
+ }
+ options.onComplete(id, xhr, isError);
+ }
+ function getParams(id) {
+ var onDemandParams = requestData[id].additionalParams, mandatedParams = options.mandatedParams, params;
+ if (options.paramsStore.get) {
+ params = options.paramsStore.get(id);
+ }
+ if (onDemandParams) {
+ qq.each(onDemandParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ if (mandatedParams) {
+ qq.each(mandatedParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ return params;
+ }
+ function sendRequest(id, optXhr) {
+ var xhr = getXhrOrXdr(id, optXhr), method = options.method, params = getParams(id), payload = requestData[id].payload, url;
+ options.onSend(id);
+ url = createUrl(id, params, requestData[id].additionalQueryParams);
+ if (isXdr(xhr)) {
+ xhr.onload = getXdrLoadHandler(id);
+ xhr.onerror = getXdrErrorHandler(id);
+ } else {
+ xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);
+ }
+ registerForUploadProgress(id);
+ xhr.open(method, url, true);
+ if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {
+ xhr.withCredentials = true;
+ }
+ setHeaders(id);
+ log("Sending " + method + " request for " + id);
+ if (payload) {
+ xhr.send(payload);
+ } else if (shouldParamsBeInQueryString || !params) {
+ xhr.send();
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/x-www-form-urlencoded") >= 0) {
+ xhr.send(qq.obj2url(params, ""));
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/json") >= 0) {
+ xhr.send(JSON.stringify(params));
+ } else {
+ xhr.send(params);
+ }
+ return xhr;
+ }
+ function createUrl(id, params, additionalQueryParams) {
+ var endpoint = options.endpointStore.get(id), addToPath = requestData[id].addToPath;
+ if (addToPath != undefined) {
+ endpoint += "/" + addToPath;
+ }
+ if (shouldParamsBeInQueryString && params) {
+ endpoint = qq.obj2url(params, endpoint);
+ }
+ if (additionalQueryParams) {
+ endpoint = qq.obj2url(additionalQueryParams, endpoint);
+ }
+ return endpoint;
+ }
+ function getXhrReadyStateChangeHandler(id) {
+ return function() {
+ if (getXhrOrXdr(id).readyState === 4) {
+ onComplete(id);
+ }
+ };
+ }
+ function registerForUploadProgress(id) {
+ var onProgress = options.onProgress;
+ if (onProgress) {
+ getXhrOrXdr(id).upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ onProgress(id, e.loaded, e.total);
+ }
+ };
+ }
+ }
+ function getXdrLoadHandler(id) {
+ return function() {
+ onComplete(id);
+ };
+ }
+ function getXdrErrorHandler(id) {
+ return function() {
+ onComplete(id, true);
+ };
+ }
+ function setHeaders(id) {
+ var xhr = getXhrOrXdr(id), customHeaders = options.customHeaders, onDemandHeaders = requestData[id].additionalHeaders || {}, method = options.method, allHeaders = {};
+ if (!isXdr(xhr)) {
+ options.acceptHeader && xhr.setRequestHeader("Accept", options.acceptHeader);
+ if (options.allowXRequestedWithAndCacheControl) {
+ if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ xhr.setRequestHeader("Cache-Control", "no-cache");
+ }
+ }
+ if (options.contentType && (method === "POST" || method === "PUT")) {
+ xhr.setRequestHeader("Content-Type", options.contentType);
+ }
+ qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);
+ qq.extend(allHeaders, onDemandHeaders);
+ qq.each(allHeaders, function(name, val) {
+ xhr.setRequestHeader(name, val);
+ });
+ }
+ }
+ function isResponseSuccessful(responseCode) {
+ return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;
+ }
+ function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {
+ requestData[id] = {
+ addToPath: addToPath,
+ additionalParams: additionalParams,
+ additionalQueryParams: additionalQueryParams,
+ additionalHeaders: additionalHeaders,
+ payload: payload
+ };
+ var len = queue.push(id);
+ if (len <= options.maxConnections) {
+ return sendRequest(id, optXhr);
+ }
+ }
+ shouldParamsBeInQueryString = options.method === "GET" || options.method === "DELETE";
+ qq.extend(this, {
+ initTransport: function(id) {
+ var path, params, headers, payload, cacheBuster, additionalQueryParams;
+ return {
+ withPath: function(appendToPath) {
+ path = appendToPath;
+ return this;
+ },
+ withParams: function(additionalParams) {
+ params = additionalParams;
+ return this;
+ },
+ withQueryParams: function(_additionalQueryParams_) {
+ additionalQueryParams = _additionalQueryParams_;
+ return this;
+ },
+ withHeaders: function(additionalHeaders) {
+ headers = additionalHeaders;
+ return this;
+ },
+ withPayload: function(thePayload) {
+ payload = thePayload;
+ return this;
+ },
+ withCacheBuster: function() {
+ cacheBuster = true;
+ return this;
+ },
+ send: function(optXhr) {
+ if (cacheBuster && qq.indexOf([ "GET", "DELETE" ], options.method) >= 0) {
+ params.qqtimestamp = new Date().getTime();
+ }
+ return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);
+ }
+ };
+ },
+ canceled: function(id) {
+ dequeue(id);
+ }
+ });
+ };
+ qq.UploadHandler = function(spec) {
+ "use strict";
+ var proxy = spec.proxy, fileState = {}, onCancel = proxy.onCancel, getName = proxy.getName;
+ qq.extend(this, {
+ add: function(id, fileItem) {
+ fileState[id] = fileItem;
+ fileState[id].temp = {};
+ },
+ cancel: function(id) {
+ var self = this, cancelFinalizationEffort = new qq.Promise(), onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);
+ onCancelRetVal.then(function() {
+ if (self.isValid(id)) {
+ fileState[id].canceled = true;
+ self.expunge(id);
+ }
+ cancelFinalizationEffort.success();
+ });
+ },
+ expunge: function(id) {
+ delete fileState[id];
+ },
+ getThirdPartyFileId: function(id) {
+ return fileState[id].key;
+ },
+ isValid: function(id) {
+ return fileState[id] !== undefined;
+ },
+ reset: function() {
+ fileState = {};
+ },
+ _getFileState: function(id) {
+ return fileState[id];
+ },
+ _setThirdPartyFileId: function(id, thirdPartyFileId) {
+ fileState[id].key = thirdPartyFileId;
+ },
+ _wasCanceled: function(id) {
+ return !!fileState[id].canceled;
+ }
+ });
+ };
+ qq.UploadHandlerController = function(o, namespace) {
+ "use strict";
+ var controller = this, chunkingPossible = false, concurrentChunkingPossible = false, chunking, preventRetryResponse, log, handler, options = {
+ paramsStore: {},
+ maxConnections: 3,
+ chunking: {
+ enabled: false,
+ multiple: {
+ enabled: false
+ }
+ },
+ log: function(str, level) {},
+ onProgress: function(id, fileName, loaded, total) {},
+ onComplete: function(id, fileName, response, xhr) {},
+ onCancel: function(id, fileName) {},
+ onUploadPrep: function(id) {},
+ onUpload: function(id, fileName) {},
+ onUploadChunk: function(id, fileName, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, response, xhr) {},
+ onAutoRetry: function(id, fileName, response, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onUuidChanged: function(id, newUuid) {},
+ getName: function(id) {},
+ setSize: function(id, newSize) {},
+ isQueued: function(id) {},
+ getIdsInProxyGroup: function(id) {},
+ getIdsInBatch: function(id) {}
+ }, chunked = {
+ done: function(id, chunkIdx, response, xhr) {
+ var chunkData = handler._getChunkData(id, chunkIdx);
+ handler._getFileState(id).attemptingResume = false;
+ delete handler._getFileState(id).temp.chunkProgress[chunkIdx];
+ handler._getFileState(id).loaded += chunkData.size;
+ options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);
+ },
+ finalize: function(id) {
+ var size = options.getSize(id), name = options.getName(id);
+ log("All chunks have been uploaded for " + id + " - finalizing....");
+ handler.finalizeChunks(id).then(function(response, xhr) {
+ log("Finalize successful for " + id);
+ var normaizedResponse = upload.normalizeResponse(response, true);
+ options.onProgress(id, name, size, size);
+ handler._maybeDeletePersistedChunkData(id);
+ upload.cleanup(id, normaizedResponse, xhr);
+ }, function(response, xhr) {
+ var normaizedResponse = upload.normalizeResponse(response, false);
+ log("Problem finalizing chunks for file ID " + id + " - " + normaizedResponse.error, "error");
+ if (normaizedResponse.reset) {
+ chunked.reset(id);
+ }
+ if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {
+ upload.cleanup(id, normaizedResponse, xhr);
+ }
+ });
+ },
+ handleFailure: function(chunkIdx, id, response, xhr) {
+ var name = options.getName(id);
+ log("Chunked upload request failed for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var responseToReport = upload.normalizeResponse(response, false), inProgressIdx;
+ if (responseToReport.reset) {
+ chunked.reset(id);
+ } else {
+ inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);
+ if (inProgressIdx >= 0) {
+ handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);
+ handler._getFileState(id).chunking.remaining.unshift(chunkIdx);
+ }
+ }
+ if (!handler._getFileState(id).temp.ignoreFailure) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = true;
+ log(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));
+ qq.each(handler._getXhrs(id), function(ckid, ckXhr) {
+ log(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ", id, ckid, ckXhr.readyState));
+ ckXhr.abort();
+ ckXhr._cancelled = true;
+ });
+ handler.moveInProgressToRemaining(id);
+ connectionManager.free(id, true);
+ }
+ if (!options.onAutoRetry(id, name, responseToReport, xhr)) {
+ upload.cleanup(id, responseToReport, xhr);
+ }
+ }
+ },
+ hasMoreParts: function(id) {
+ return !!handler._getFileState(id).chunking.remaining.length;
+ },
+ nextPart: function(id) {
+ var nextIdx = handler._getFileState(id).chunking.remaining.shift();
+ if (nextIdx >= handler._getTotalChunks(id)) {
+ nextIdx = null;
+ }
+ return nextIdx;
+ },
+ reset: function(id) {
+ log("Server or callback has ordered chunking effort to be restarted on next attempt for item ID " + id, "error");
+ handler._maybeDeletePersistedChunkData(id);
+ handler.reevaluateChunking(id);
+ handler._getFileState(id).loaded = 0;
+ },
+ sendNext: function(id) {
+ var size = options.getSize(id), name = options.getName(id), chunkIdx = chunked.nextPart(id), chunkData = handler._getChunkData(id, chunkIdx), resuming = handler._getFileState(id).attemptingResume, inProgressChunks = handler._getFileState(id).chunking.inProgress || [];
+ if (handler._getFileState(id).loaded == null) {
+ handler._getFileState(id).loaded = 0;
+ }
+ if (resuming && options.onResume(id, name, chunkData) === false) {
+ chunked.reset(id);
+ chunkIdx = chunked.nextPart(id);
+ chunkData = handler._getChunkData(id, chunkIdx);
+ resuming = false;
+ }
+ if (chunkIdx == null && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else {
+ log(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.", id, chunkIdx, chunkData.start + 1, chunkData.end, size));
+ options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));
+ inProgressChunks.push(chunkIdx);
+ handler._getFileState(id).chunking.inProgress = inProgressChunks;
+ if (concurrentChunkingPossible) {
+ connectionManager.open(id, chunkIdx);
+ }
+ if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {
+ chunked.sendNext(id);
+ }
+ if (chunkData.blob.size === 0) {
+ log(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.", chunkIdx, id), "error");
+ chunked.handleFailure(chunkIdx, id, "File is no longer available", null);
+ } else {
+ handler.uploadChunk(id, chunkIdx, resuming).then(function success(response, xhr) {
+ log("Chunked upload request succeeded for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var inProgressChunks = handler._getFileState(id).chunking.inProgress || [], responseToReport = upload.normalizeResponse(response, true), inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);
+ log(qq.format("Chunk {} for file {} uploaded successfully.", chunkIdx, id));
+ chunked.done(id, chunkIdx, responseToReport, xhr);
+ if (inProgressChunkIdx >= 0) {
+ inProgressChunks.splice(inProgressChunkIdx, 1);
+ }
+ handler._maybePersistChunkedState(id);
+ if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else if (chunked.hasMoreParts(id)) {
+ chunked.sendNext(id);
+ } else {
+ log(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}", id, JSON.stringify(inProgressChunks)));
+ }
+ }, function failure(response, xhr) {
+ chunked.handleFailure(chunkIdx, id, response, xhr);
+ }).done(function() {
+ handler.clearXhr(id, chunkIdx);
+ });
+ }
+ }
+ }
+ }, connectionManager = {
+ _open: [],
+ _openChunks: {},
+ _waiting: [],
+ available: function() {
+ var max = options.maxConnections, openChunkEntriesCount = 0, openChunksCount = 0;
+ qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {
+ openChunkEntriesCount++;
+ openChunksCount += openChunkIndexes.length;
+ });
+ return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);
+ },
+ free: function(id, dontAllowNext) {
+ var allowNext = !dontAllowNext, waitingIndex = qq.indexOf(connectionManager._waiting, id), connectionsIndex = qq.indexOf(connectionManager._open, id), nextId;
+ delete connectionManager._openChunks[id];
+ if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {
+ log("Generated blob upload has ended for " + id + ", disposing generated blob.");
+ delete handler._getFileState(id).file;
+ }
+ if (waitingIndex >= 0) {
+ connectionManager._waiting.splice(waitingIndex, 1);
+ } else if (allowNext && connectionsIndex >= 0) {
+ connectionManager._open.splice(connectionsIndex, 1);
+ nextId = connectionManager._waiting.shift();
+ if (nextId >= 0) {
+ connectionManager._open.push(nextId);
+ upload.start(nextId);
+ }
+ }
+ },
+ getWaitingOrConnected: function() {
+ var waitingOrConnected = [];
+ qq.each(connectionManager._openChunks, function(fileId, chunks) {
+ if (chunks && chunks.length) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ qq.each(connectionManager._open, function(idx, fileId) {
+ if (!connectionManager._openChunks[fileId]) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);
+ return waitingOrConnected;
+ },
+ isUsingConnection: function(id) {
+ return qq.indexOf(connectionManager._open, id) >= 0;
+ },
+ open: function(id, chunkIdx) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.push(id);
+ }
+ if (connectionManager.available()) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.pop();
+ connectionManager._open.push(id);
+ } else {
+ (function() {
+ var openChunksEntry = connectionManager._openChunks[id] || [];
+ openChunksEntry.push(chunkIdx);
+ connectionManager._openChunks[id] = openChunksEntry;
+ })();
+ }
+ return true;
+ }
+ return false;
+ },
+ reset: function() {
+ connectionManager._waiting = [];
+ connectionManager._open = [];
+ }
+ }, simple = {
+ send: function(id, name) {
+ handler._getFileState(id).loaded = 0;
+ log("Sending simple upload request for " + id);
+ handler.uploadFile(id).then(function(response, optXhr) {
+ log("Simple upload request succeeded for " + id);
+ var responseToReport = upload.normalizeResponse(response, true), size = options.getSize(id);
+ options.onProgress(id, name, size, size);
+ upload.maybeNewUuid(id, responseToReport);
+ upload.cleanup(id, responseToReport, optXhr);
+ }, function(response, optXhr) {
+ log("Simple upload request failed for " + id);
+ var responseToReport = upload.normalizeResponse(response, false);
+ if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {
+ upload.cleanup(id, responseToReport, optXhr);
+ }
+ });
+ }
+ }, upload = {
+ cancel: function(id) {
+ log("Cancelling " + id);
+ options.paramsStore.remove(id);
+ connectionManager.free(id);
+ },
+ cleanup: function(id, response, optXhr) {
+ var name = options.getName(id);
+ options.onComplete(id, name, response, optXhr);
+ if (handler._getFileState(id)) {
+ handler._clearXhrs && handler._clearXhrs(id);
+ }
+ connectionManager.free(id);
+ },
+ getProxyOrBlob: function(id) {
+ return handler.getProxy && handler.getProxy(id) || handler.getFile && handler.getFile(id);
+ },
+ initHandler: function() {
+ var handlerType = namespace ? qq[namespace] : qq.traditional, handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? "Xhr" : "Form";
+ handler = new handlerType[handlerModuleSubtype + "UploadHandler"](options, {
+ getDataByUuid: options.getDataByUuid,
+ getName: options.getName,
+ getSize: options.getSize,
+ getUuid: options.getUuid,
+ log: log,
+ onCancel: options.onCancel,
+ onProgress: options.onProgress,
+ onUuidChanged: options.onUuidChanged
+ });
+ if (handler._removeExpiredChunkingRecords) {
+ handler._removeExpiredChunkingRecords();
+ }
+ },
+ isDeferredEligibleForUpload: function(id) {
+ return options.isQueued(id);
+ },
+ maybeDefer: function(id, blob) {
+ if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {
+ options.onUploadPrep(id);
+ log("Attempting to generate a blob on-demand for " + id);
+ blob.create().then(function(generatedBlob) {
+ log("Generated an on-demand blob for " + id);
+ handler.updateBlob(id, generatedBlob);
+ options.setSize(id, generatedBlob.size);
+ handler.reevaluateChunking(id);
+ upload.maybeSendDeferredFiles(id);
+ }, function(errorMessage) {
+ var errorResponse = {};
+ if (errorMessage) {
+ errorResponse.error = errorMessage;
+ }
+ log(qq.format("Failed to generate blob for ID {}. Error message: {}.", id, errorMessage), "error");
+ options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);
+ upload.maybeSendDeferredFiles(id);
+ connectionManager.free(id);
+ });
+ } else {
+ return upload.maybeSendDeferredFiles(id);
+ }
+ return false;
+ },
+ maybeSendDeferredFiles: function(id) {
+ var idsInGroup = options.getIdsInProxyGroup(id), uploadedThisId = false;
+ if (idsInGroup && idsInGroup.length) {
+ log("Maybe ready to upload proxy group file " + id);
+ qq.each(idsInGroup, function(idx, idInGroup) {
+ if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {
+ uploadedThisId = idInGroup === id;
+ upload.now(idInGroup);
+ } else if (upload.isDeferredEligibleForUpload(idInGroup)) {
+ return false;
+ }
+ });
+ } else {
+ uploadedThisId = true;
+ upload.now(id);
+ }
+ return uploadedThisId;
+ },
+ maybeNewUuid: function(id, response) {
+ if (response.newUuid !== undefined) {
+ options.onUuidChanged(id, response.newUuid);
+ }
+ },
+ normalizeResponse: function(originalResponse, successful) {
+ var response = originalResponse;
+ if (!qq.isObject(originalResponse)) {
+ response = {};
+ if (qq.isString(originalResponse) && !successful) {
+ response.error = originalResponse;
+ }
+ }
+ response.success = successful;
+ return response;
+ },
+ now: function(id) {
+ var name = options.getName(id);
+ if (!controller.isValid(id)) {
+ throw new qq.Error(id + " is not a valid file ID to upload!");
+ }
+ options.onUpload(id, name);
+ if (chunkingPossible && handler._shouldChunkThisFile(id)) {
+ chunked.sendNext(id);
+ } else {
+ simple.send(id, name);
+ }
+ },
+ start: function(id) {
+ var blobToUpload = upload.getProxyOrBlob(id);
+ if (blobToUpload) {
+ return upload.maybeDefer(id, blobToUpload);
+ } else {
+ upload.now(id);
+ return true;
+ }
+ }
+ };
+ qq.extend(this, {
+ add: function(id, file) {
+ handler.add.apply(this, arguments);
+ },
+ upload: function(id) {
+ if (connectionManager.open(id)) {
+ return upload.start(id);
+ }
+ return false;
+ },
+ retry: function(id) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = false;
+ }
+ if (connectionManager.isUsingConnection(id)) {
+ return upload.start(id);
+ } else {
+ return controller.upload(id);
+ }
+ },
+ cancel: function(id) {
+ var cancelRetVal = handler.cancel(id);
+ if (qq.isGenericPromise(cancelRetVal)) {
+ cancelRetVal.then(function() {
+ upload.cancel(id);
+ });
+ } else if (cancelRetVal !== false) {
+ upload.cancel(id);
+ }
+ },
+ cancelAll: function() {
+ var waitingOrConnected = connectionManager.getWaitingOrConnected(), i;
+ if (waitingOrConnected.length) {
+ for (i = waitingOrConnected.length - 1; i >= 0; i--) {
+ controller.cancel(waitingOrConnected[i]);
+ }
+ }
+ connectionManager.reset();
+ },
+ getFile: function(id) {
+ if (handler.getProxy && handler.getProxy(id)) {
+ return handler.getProxy(id).referenceBlob;
+ }
+ return handler.getFile && handler.getFile(id);
+ },
+ isProxied: function(id) {
+ return !!(handler.getProxy && handler.getProxy(id));
+ },
+ getInput: function(id) {
+ if (handler.getInput) {
+ return handler.getInput(id);
+ }
+ },
+ reset: function() {
+ log("Resetting upload handler");
+ controller.cancelAll();
+ connectionManager.reset();
+ handler.reset();
+ },
+ expunge: function(id) {
+ if (controller.isValid(id)) {
+ return handler.expunge(id);
+ }
+ },
+ isValid: function(id) {
+ return handler.isValid(id);
+ },
+ getResumableFilesData: function() {
+ if (handler.getResumableFilesData) {
+ return handler.getResumableFilesData();
+ }
+ return [];
+ },
+ getThirdPartyFileId: function(id) {
+ if (controller.isValid(id)) {
+ return handler.getThirdPartyFileId(id);
+ }
+ },
+ pause: function(id) {
+ if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {
+ connectionManager.free(id);
+ handler.moveInProgressToRemaining(id);
+ return true;
+ }
+ return false;
+ },
+ isResumable: function(id) {
+ return !!handler.isResumable && handler.isResumable(id);
+ }
+ });
+ qq.extend(options, o);
+ log = options.log;
+ chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;
+ concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;
+ preventRetryResponse = function() {
+ var response = {};
+ response[options.preventRetryParam] = true;
+ return response;
+ }();
+ upload.initHandler();
+ };
+ qq.WindowReceiveMessage = function(o) {
+ "use strict";
+ var options = {
+ log: function(message, level) {}
+ }, callbackWrapperDetachers = {};
+ qq.extend(options, o);
+ qq.extend(this, {
+ receiveMessage: function(id, callback) {
+ var onMessageCallbackWrapper = function(event) {
+ callback(event.data);
+ };
+ if (window.postMessage) {
+ callbackWrapperDetachers[id] = qq(window).attach("message", onMessageCallbackWrapper);
+ } else {
+ log("iframe message passing not supported in this browser!", "error");
+ }
+ },
+ stopReceivingMessages: function(id) {
+ if (window.postMessage) {
+ var detacher = callbackWrapperDetachers[id];
+ if (detacher) {
+ detacher();
+ }
+ }
+ }
+ });
+ };
+ qq.FormUploadHandler = function(spec) {
+ "use strict";
+ var options = spec.options, handler = this, proxy = spec.proxy, formHandlerInstanceId = qq.getUniqueId(), onloadCallbacks = {}, detachLoadEvents = {}, postMessageCallbackTimers = {}, isCors = options.isCors, inputName = options.inputName, getUuid = proxy.getUuid, log = proxy.log, corsMessageReceiver = new qq.WindowReceiveMessage({
+ log: log
+ });
+ function expungeFile(id) {
+ delete detachLoadEvents[id];
+ if (isCors) {
+ clearTimeout(postMessageCallbackTimers[id]);
+ delete postMessageCallbackTimers[id];
+ corsMessageReceiver.stopReceivingMessages(id);
+ }
+ var iframe = document.getElementById(handler._getIframeName(id));
+ if (iframe) {
+ iframe.setAttribute("src", "javascript:false;");
+ qq(iframe).remove();
+ }
+ }
+ function getFileIdForIframeName(iframeName) {
+ return iframeName.split("_")[0];
+ }
+ function initIframeForUpload(name) {
+ var iframe = qq.toElement("");
+ iframe.setAttribute("id", name);
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+ return iframe;
+ }
+ function registerPostMessageCallback(iframe, callback) {
+ var iframeName = iframe.id, fileId = getFileIdForIframeName(iframeName), uuid = getUuid(fileId);
+ onloadCallbacks[uuid] = callback;
+ detachLoadEvents[fileId] = qq(iframe).attach("load", function() {
+ if (handler.getInput(fileId)) {
+ log("Received iframe load event for CORS upload request (iframe name " + iframeName + ")");
+ postMessageCallbackTimers[iframeName] = setTimeout(function() {
+ var errorMessage = "No valid message received from loaded iframe for iframe name " + iframeName;
+ log(errorMessage, "error");
+ callback({
+ error: errorMessage
+ });
+ }, 1e3);
+ }
+ });
+ corsMessageReceiver.receiveMessage(iframeName, function(message) {
+ log("Received the following window message: '" + message + "'");
+ var fileId = getFileIdForIframeName(iframeName), response = handler._parseJsonResponse(message), uuid = response.uuid, onloadCallback;
+ if (uuid && onloadCallbacks[uuid]) {
+ log("Handling response for iframe name " + iframeName);
+ clearTimeout(postMessageCallbackTimers[iframeName]);
+ delete postMessageCallbackTimers[iframeName];
+ handler._detachLoadEvent(iframeName);
+ onloadCallback = onloadCallbacks[uuid];
+ delete onloadCallbacks[uuid];
+ corsMessageReceiver.stopReceivingMessages(iframeName);
+ onloadCallback(response);
+ } else if (!uuid) {
+ log("'" + message + "' does not contain a UUID - ignoring.");
+ }
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, fileInput) {
+ super_.add(id, {
+ input: fileInput
+ });
+ fileInput.setAttribute("name", inputName);
+ if (fileInput.parentNode) {
+ qq(fileInput).remove();
+ }
+ },
+ expunge: function(id) {
+ expungeFile(id);
+ super_.expunge(id);
+ },
+ isValid: function(id) {
+ return super_.isValid(id) && handler._getFileState(id).input !== undefined;
+ }
+ };
+ });
+ qq.extend(this, {
+ getInput: function(id) {
+ return handler._getFileState(id).input;
+ },
+ _attachLoadEvent: function(iframe, callback) {
+ var responseDescriptor;
+ if (isCors) {
+ registerPostMessageCallback(iframe, callback);
+ } else {
+ detachLoadEvents[iframe.id] = qq(iframe).attach("load", function() {
+ log("Received response for " + iframe.id);
+ if (!iframe.parentNode) {
+ return;
+ }
+ try {
+ if (iframe.contentDocument && iframe.contentDocument.body && iframe.contentDocument.body.innerHTML == "false") {
+ return;
+ }
+ } catch (error) {
+ log("Error when attempting to access iframe during handling of upload response (" + error.message + ")", "error");
+ responseDescriptor = {
+ success: false
+ };
+ }
+ callback(responseDescriptor);
+ });
+ }
+ },
+ _createIframe: function(id) {
+ var iframeName = handler._getIframeName(id);
+ return initIframeForUpload(iframeName);
+ },
+ _detachLoadEvent: function(id) {
+ if (detachLoadEvents[id] !== undefined) {
+ detachLoadEvents[id]();
+ delete detachLoadEvents[id];
+ }
+ },
+ _getIframeName: function(fileId) {
+ return fileId + "_" + formHandlerInstanceId;
+ },
+ _initFormForUpload: function(spec) {
+ var method = spec.method, endpoint = spec.endpoint, params = spec.params, paramsInBody = spec.paramsInBody, targetName = spec.targetName, form = qq.toElement(""), url = endpoint;
+ if (paramsInBody) {
+ qq.obj2Inputs(params, form);
+ } else {
+ url = qq.obj2url(params, endpoint);
+ }
+ form.setAttribute("action", url);
+ form.setAttribute("target", targetName);
+ form.style.display = "none";
+ document.body.appendChild(form);
+ return form;
+ },
+ _parseJsonResponse: function(innerHtmlOrMessage) {
+ var response = {};
+ try {
+ response = qq.parseJson(innerHtmlOrMessage);
+ } catch (error) {
+ log("Error when attempting to parse iframe upload response (" + error.message + ")", "error");
+ }
+ return response;
+ }
+ });
+ };
+ qq.XhrUploadHandler = function(spec) {
+ "use strict";
+ var handler = this, namespace = spec.options.namespace, proxy = spec.proxy, chunking = spec.options.chunking, resume = spec.options.resume, chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking, resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume, getName = proxy.getName, getSize = proxy.getSize, getUuid = proxy.getUuid, getEndpoint = proxy.getEndpoint, getDataByUuid = proxy.getDataByUuid, onUuidChanged = proxy.onUuidChanged, onProgress = proxy.onProgress, log = proxy.log;
+ function abort(id) {
+ qq.each(handler._getXhrs(id), function(xhrId, xhr) {
+ var ajaxRequester = handler._getAjaxRequester(id, xhrId);
+ xhr.onreadystatechange = null;
+ xhr.upload.onprogress = null;
+ xhr.abort();
+ ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, blobOrProxy) {
+ if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {
+ super_.add(id, {
+ file: blobOrProxy
+ });
+ } else if (blobOrProxy instanceof qq.BlobProxy) {
+ super_.add(id, {
+ proxy: blobOrProxy
+ });
+ } else {
+ throw new Error("Passed obj is not a File, Blob, or proxy");
+ }
+ handler._initTempState(id);
+ resumeEnabled && handler._maybePrepareForResume(id);
+ },
+ expunge: function(id) {
+ abort(id);
+ handler._maybeDeletePersistedChunkData(id);
+ handler._clearXhrs(id);
+ super_.expunge(id);
+ }
+ };
+ });
+ qq.extend(this, {
+ clearCachedChunk: function(id, chunkIdx) {
+ delete handler._getFileState(id).temp.cachedChunks[chunkIdx];
+ },
+ clearXhr: function(id, chunkIdx) {
+ var tempState = handler._getFileState(id).temp;
+ if (tempState.xhrs) {
+ delete tempState.xhrs[chunkIdx];
+ }
+ if (tempState.ajaxRequesters) {
+ delete tempState.ajaxRequesters[chunkIdx];
+ }
+ },
+ finalizeChunks: function(id, responseParser) {
+ var lastChunkIdx = handler._getTotalChunks(id) - 1, xhr = handler._getXhr(id, lastChunkIdx);
+ if (responseParser) {
+ return new qq.Promise().success(responseParser(xhr), xhr);
+ }
+ return new qq.Promise().success({}, xhr);
+ },
+ getFile: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).file;
+ },
+ getProxy: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).proxy;
+ },
+ getResumableFilesData: function() {
+ var resumableFilesData = [];
+ handler._iterateResumeRecords(function(key, uploadData) {
+ handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);
+ var data = {
+ name: uploadData.name,
+ remaining: uploadData.chunking.remaining,
+ size: uploadData.size,
+ uuid: uploadData.uuid
+ };
+ if (uploadData.key) {
+ data.key = uploadData.key;
+ }
+ resumableFilesData.push(data);
+ });
+ return resumableFilesData;
+ },
+ isResumable: function(id) {
+ return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;
+ },
+ moveInProgressToRemaining: function(id, optInProgress, optRemaining) {
+ var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress, remaining = optRemaining || handler._getFileState(id).chunking.remaining;
+ if (inProgress) {
+ log(qq.format("Moving these chunks from in-progress {}, to remaining.", JSON.stringify(inProgress)));
+ inProgress.reverse();
+ qq.each(inProgress, function(idx, chunkIdx) {
+ remaining.unshift(chunkIdx);
+ });
+ inProgress.length = 0;
+ }
+ },
+ pause: function(id) {
+ if (handler.isValid(id)) {
+ log(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.", id, getName(id)));
+ handler._getFileState(id).paused = true;
+ abort(id);
+ return true;
+ }
+ },
+ reevaluateChunking: function(id) {
+ if (chunking && handler.isValid(id)) {
+ var state = handler._getFileState(id), totalChunks, i;
+ delete state.chunking;
+ state.chunking = {};
+ totalChunks = handler._getTotalChunks(id);
+ if (totalChunks > 1 || chunking.mandatory) {
+ state.chunking.enabled = true;
+ state.chunking.parts = totalChunks;
+ state.chunking.remaining = [];
+ for (i = 0; i < totalChunks; i++) {
+ state.chunking.remaining.push(i);
+ }
+ handler._initTempState(id);
+ } else {
+ state.chunking.enabled = false;
+ }
+ }
+ },
+ updateBlob: function(id, newBlob) {
+ if (handler.isValid(id)) {
+ handler._getFileState(id).file = newBlob;
+ }
+ },
+ _clearXhrs: function(id) {
+ var tempState = handler._getFileState(id).temp;
+ qq.each(tempState.ajaxRequesters, function(chunkId) {
+ delete tempState.ajaxRequesters[chunkId];
+ });
+ qq.each(tempState.xhrs, function(chunkId) {
+ delete tempState.xhrs[chunkId];
+ });
+ },
+ _createXhr: function(id, optChunkIdx) {
+ return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());
+ },
+ _getAjaxRequester: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];
+ },
+ _getChunkData: function(id, chunkIndex) {
+ var chunkSize = chunking.partSize, fileSize = getSize(id), fileOrBlob = handler.getFile(id), startBytes = chunkSize * chunkIndex, endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize, totalChunks = handler._getTotalChunks(id), cachedChunks = this._getFileState(id).temp.cachedChunks, blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);
+ cachedChunks[chunkIndex] = blob;
+ return {
+ part: chunkIndex,
+ start: startBytes,
+ end: endBytes,
+ count: totalChunks,
+ blob: blob,
+ size: endBytes - startBytes
+ };
+ },
+ _getChunkDataForCallback: function(chunkData) {
+ return {
+ partIndex: chunkData.part,
+ startByte: chunkData.start + 1,
+ endByte: chunkData.end,
+ totalParts: chunkData.count
+ };
+ },
+ _getLocalStorageId: function(id) {
+ var formatVersion = "5.0", name = getName(id), size = getSize(id), chunkSize = chunking.partSize, endpoint = getEndpoint(id);
+ return qq.format("qq{}resume{}-{}-{}-{}-{}", namespace, formatVersion, name, size, chunkSize, endpoint);
+ },
+ _getMimeType: function(id) {
+ return handler.getFile(id).type;
+ },
+ _getPersistableData: function(id) {
+ return handler._getFileState(id).chunking;
+ },
+ _getTotalChunks: function(id) {
+ if (chunking) {
+ var fileSize = getSize(id), chunkSize = chunking.partSize;
+ return Math.ceil(fileSize / chunkSize);
+ }
+ },
+ _getXhr: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.xhrs[chunkIdx];
+ },
+ _getXhrs: function(id) {
+ return handler._getFileState(id).temp.xhrs;
+ },
+ _iterateResumeRecords: function(callback) {
+ if (resumeEnabled) {
+ qq.each(localStorage, function(key, item) {
+ if (key.indexOf(qq.format("qq{}resume", namespace)) === 0) {
+ var uploadData = JSON.parse(item);
+ callback(key, uploadData);
+ }
+ });
+ }
+ },
+ _initTempState: function(id) {
+ handler._getFileState(id).temp = {
+ ajaxRequesters: {},
+ chunkProgress: {},
+ xhrs: {},
+ cachedChunks: {}
+ };
+ },
+ _markNotResumable: function(id) {
+ handler._getFileState(id).notResumable = true;
+ },
+ _maybeDeletePersistedChunkData: function(id) {
+ var localStorageId;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ if (localStorageId && localStorage.getItem(localStorageId)) {
+ localStorage.removeItem(localStorageId);
+ return true;
+ }
+ }
+ return false;
+ },
+ _maybePrepareForResume: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && state.key === undefined) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = localStorage.getItem(localStorageId);
+ if (persistedData) {
+ persistedData = JSON.parse(persistedData);
+ if (getDataByUuid(persistedData.uuid)) {
+ handler._markNotResumable(id);
+ } else {
+ log(qq.format("Identified file with ID {} and name of {} as resumable.", id, getName(id)));
+ onUuidChanged(id, persistedData.uuid);
+ state.key = persistedData.key;
+ state.chunking = persistedData.chunking;
+ state.loaded = persistedData.loaded;
+ state.attemptingResume = true;
+ handler.moveInProgressToRemaining(id);
+ }
+ }
+ }
+ },
+ _maybePersistChunkedState: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = {
+ name: getName(id),
+ size: getSize(id),
+ uuid: getUuid(id),
+ key: state.key,
+ chunking: state.chunking,
+ loaded: state.loaded,
+ lastUpdated: Date.now()
+ };
+ try {
+ localStorage.setItem(localStorageId, JSON.stringify(persistedData));
+ } catch (error) {
+ log(qq.format("Unable to save resume data for '{}' due to error: '{}'.", id, error.toString()), "warn");
+ }
+ }
+ },
+ _registerProgressHandler: function(id, chunkIdx, chunkSize) {
+ var xhr = handler._getXhr(id, chunkIdx), name = getName(id), progressCalculator = {
+ simple: function(loaded, total) {
+ var fileSize = getSize(id);
+ if (loaded === total) {
+ onProgress(id, name, fileSize, fileSize);
+ } else {
+ onProgress(id, name, loaded >= fileSize ? fileSize - 1 : loaded, fileSize);
+ }
+ },
+ chunked: function(loaded, total) {
+ var chunkProgress = handler._getFileState(id).temp.chunkProgress, totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded, loadedForRequest = loaded, totalForRequest = total, totalFileSize = getSize(id), estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize), totalLoadedForFile = totalSuccessfullyLoadedForFile;
+ chunkProgress[chunkIdx] = estActualChunkLoaded;
+ qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {
+ totalLoadedForFile += chunkLoaded;
+ });
+ onProgress(id, name, totalLoadedForFile, totalFileSize);
+ }
+ };
+ xhr.upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ var type = chunkSize == null ? "simple" : "chunked";
+ progressCalculator[type](e.loaded, e.total);
+ }
+ };
+ },
+ _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {
+ var xhrsId = optChunkIdx == null ? -1 : optChunkIdx, tempState = handler._getFileState(id).temp;
+ tempState.xhrs = tempState.xhrs || {};
+ tempState.ajaxRequesters = tempState.ajaxRequesters || {};
+ tempState.xhrs[xhrsId] = xhr;
+ if (optAjaxRequester) {
+ tempState.ajaxRequesters[xhrsId] = optAjaxRequester;
+ }
+ return xhr;
+ },
+ _removeExpiredChunkingRecords: function() {
+ var expirationDays = resume.recordsExpireIn;
+ handler._iterateResumeRecords(function(key, uploadData) {
+ var expirationDate = new Date(uploadData.lastUpdated);
+ expirationDate.setDate(expirationDate.getDate() + expirationDays);
+ if (expirationDate.getTime() <= Date.now()) {
+ log("Removing expired resume record with key " + key);
+ localStorage.removeItem(key);
+ }
+ });
+ },
+ _shouldChunkThisFile: function(id) {
+ var state = handler._getFileState(id);
+ if (!state.chunking) {
+ handler.reevaluateChunking(id);
+ }
+ return state.chunking.enabled;
+ }
+ });
+ };
+ qq.DeleteFileAjaxRequester = function(o) {
+ "use strict";
+ var requester, options = {
+ method: "DELETE",
+ uuidParamName: "qquuid",
+ endpointStore: {},
+ maxConnections: 3,
+ customHeaders: function(id) {
+ return {};
+ },
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {}
+ };
+ qq.extend(options, o);
+ function getMandatedParams() {
+ if (options.method.toUpperCase() === "POST") {
+ return {
+ _method: "DELETE"
+ };
+ }
+ return {};
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "POST", "DELETE" ],
+ method: options.method,
+ endpointStore: options.endpointStore,
+ paramsStore: options.paramsStore,
+ mandatedParams: getMandatedParams(),
+ maxConnections: options.maxConnections,
+ customHeaders: function(id) {
+ return options.customHeaders.get(id);
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendDelete: function(id, uuid, additionalMandatedParams) {
+ var additionalOptions = additionalMandatedParams || {};
+ options.log("Submitting delete file request for " + id);
+ if (options.method === "DELETE") {
+ requester.initTransport(id).withPath(uuid).withParams(additionalOptions).send();
+ } else {
+ additionalOptions[options.uuidParamName] = uuid;
+ requester.initTransport(id).withParams(additionalOptions).send();
+ }
+ }
+ });
+ };
+ (function() {
+ function detectSubsampling(img) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, canvas = document.createElement("canvas"), ctx;
+ if (iw * ih > 1024 * 1024) {
+ canvas.width = canvas.height = 1;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, -iw + 1, 0);
+ return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+ } else {
+ return false;
+ }
+ }
+ function detectVerticalSquash(img, iw, ih) {
+ var canvas = document.createElement("canvas"), sy = 0, ey = ih, py = ih, ctx, data, alpha, ratio;
+ canvas.width = 1;
+ canvas.height = ih;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, 0, 0);
+ data = ctx.getImageData(0, 0, 1, ih).data;
+ while (py > sy) {
+ alpha = data[(py - 1) * 4 + 3];
+ if (alpha === 0) {
+ ey = py;
+ } else {
+ sy = py;
+ }
+ py = ey + sy >> 1;
+ }
+ ratio = py / ih;
+ return ratio === 0 ? 1 : ratio;
+ }
+ function renderImageToDataURL(img, blob, options, doSquash) {
+ var canvas = document.createElement("canvas"), mime = options.mime || "image/jpeg", promise = new qq.Promise();
+ renderImageToCanvas(img, blob, canvas, options, doSquash).then(function() {
+ promise.success(canvas.toDataURL(mime, options.quality || .8));
+ });
+ return promise;
+ }
+ function maybeCalculateDownsampledDimensions(spec) {
+ var maxPixels = 5241e3;
+ if (!qq.ios()) {
+ throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");
+ }
+ if (spec.origHeight * spec.origWidth > maxPixels) {
+ return {
+ newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),
+ newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))
+ };
+ }
+ }
+ function renderImageToCanvas(img, blob, canvas, options, doSquash) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, width = options.width, height = options.height, ctx = canvas.getContext("2d"), promise = new qq.Promise(), modifiedDimensions;
+ ctx.save();
+ if (options.resize) {
+ return renderImageToCanvasWithCustomResizer({
+ blob: blob,
+ canvas: canvas,
+ image: img,
+ imageHeight: ih,
+ imageWidth: iw,
+ orientation: options.orientation,
+ resize: options.resize,
+ targetHeight: height,
+ targetWidth: width
+ });
+ }
+ if (!qq.supportedFeatures.unlimitedScaledImageSize) {
+ modifiedDimensions = maybeCalculateDownsampledDimensions({
+ origWidth: width,
+ origHeight: height
+ });
+ if (modifiedDimensions) {
+ qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h", width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight), "warn");
+ width = modifiedDimensions.newWidth;
+ height = modifiedDimensions.newHeight;
+ }
+ }
+ transformCoordinate(canvas, width, height, options.orientation);
+ if (qq.ios()) {
+ (function() {
+ if (detectSubsampling(img)) {
+ iw /= 2;
+ ih /= 2;
+ }
+ var d = 1024, tmpCanvas = document.createElement("canvas"), vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1, dw = Math.ceil(d * width / iw), dh = Math.ceil(d * height / ih / vertSquashRatio), sy = 0, dy = 0, tmpCtx, sx, dx;
+ tmpCanvas.width = tmpCanvas.height = d;
+ tmpCtx = tmpCanvas.getContext("2d");
+ while (sy < ih) {
+ sx = 0;
+ dx = 0;
+ while (sx < iw) {
+ tmpCtx.clearRect(0, 0, d, d);
+ tmpCtx.drawImage(img, -sx, -sy);
+ ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);
+ sx += d;
+ dx += dw;
+ }
+ sy += d;
+ dy += dh;
+ }
+ ctx.restore();
+ tmpCanvas = tmpCtx = null;
+ })();
+ } else {
+ ctx.drawImage(img, 0, 0, width, height);
+ }
+ canvas.qqImageRendered && canvas.qqImageRendered();
+ promise.success();
+ return promise;
+ }
+ function renderImageToCanvasWithCustomResizer(resizeInfo) {
+ var blob = resizeInfo.blob, image = resizeInfo.image, imageHeight = resizeInfo.imageHeight, imageWidth = resizeInfo.imageWidth, orientation = resizeInfo.orientation, promise = new qq.Promise(), resize = resizeInfo.resize, sourceCanvas = document.createElement("canvas"), sourceCanvasContext = sourceCanvas.getContext("2d"), targetCanvas = resizeInfo.canvas, targetHeight = resizeInfo.targetHeight, targetWidth = resizeInfo.targetWidth;
+ transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);
+ targetCanvas.height = targetHeight;
+ targetCanvas.width = targetWidth;
+ sourceCanvasContext.drawImage(image, 0, 0);
+ resize({
+ blob: blob,
+ height: targetHeight,
+ image: image,
+ sourceCanvas: sourceCanvas,
+ targetCanvas: targetCanvas,
+ width: targetWidth
+ }).then(function success() {
+ targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();
+ promise.success();
+ }, promise.failure);
+ return promise;
+ }
+ function transformCoordinate(canvas, width, height, orientation) {
+ switch (orientation) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ canvas.width = height;
+ canvas.height = width;
+ break;
+
+ default:
+ canvas.width = width;
+ canvas.height = height;
+ }
+ var ctx = canvas.getContext("2d");
+ switch (orientation) {
+ case 2:
+ ctx.translate(width, 0);
+ ctx.scale(-1, 1);
+ break;
+
+ case 3:
+ ctx.translate(width, height);
+ ctx.rotate(Math.PI);
+ break;
+
+ case 4:
+ ctx.translate(0, height);
+ ctx.scale(1, -1);
+ break;
+
+ case 5:
+ ctx.rotate(.5 * Math.PI);
+ ctx.scale(1, -1);
+ break;
+
+ case 6:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(0, -height);
+ break;
+
+ case 7:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(width, -height);
+ ctx.scale(-1, 1);
+ break;
+
+ case 8:
+ ctx.rotate(-.5 * Math.PI);
+ ctx.translate(-width, 0);
+ break;
+
+ default:
+ break;
+ }
+ }
+ function MegaPixImage(srcImage, errorCallback) {
+ var self = this;
+ if (window.Blob && srcImage instanceof Blob) {
+ (function() {
+ var img = new Image(), URL = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (!URL) {
+ throw Error("No createObjectURL function found to create blob url");
+ }
+ img.src = URL.createObjectURL(srcImage);
+ self.blob = srcImage;
+ srcImage = img;
+ })();
+ }
+ if (!srcImage.naturalWidth && !srcImage.naturalHeight) {
+ srcImage.onload = function() {
+ var listeners = self.imageLoadListeners;
+ if (listeners) {
+ self.imageLoadListeners = null;
+ setTimeout(function() {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i]();
+ }
+ }, 0);
+ }
+ };
+ srcImage.onerror = errorCallback;
+ this.imageLoadListeners = [];
+ }
+ this.srcImage = srcImage;
+ }
+ MegaPixImage.prototype.render = function(target, options) {
+ options = options || {};
+ var self = this, imgWidth = this.srcImage.naturalWidth, imgHeight = this.srcImage.naturalHeight, width = options.width, height = options.height, maxWidth = options.maxWidth, maxHeight = options.maxHeight, doSquash = !this.blob || this.blob.type === "image/jpeg", tagName = target.tagName.toLowerCase(), opt;
+ if (this.imageLoadListeners) {
+ this.imageLoadListeners.push(function() {
+ self.render(target, options);
+ });
+ return;
+ }
+ if (width && !height) {
+ height = imgHeight * width / imgWidth << 0;
+ } else if (height && !width) {
+ width = imgWidth * height / imgHeight << 0;
+ } else {
+ width = imgWidth;
+ height = imgHeight;
+ }
+ if (maxWidth && width > maxWidth) {
+ width = maxWidth;
+ height = imgHeight * width / imgWidth << 0;
+ }
+ if (maxHeight && height > maxHeight) {
+ height = maxHeight;
+ width = imgWidth * height / imgHeight << 0;
+ }
+ opt = {
+ width: width,
+ height: height
+ }, qq.each(options, function(optionsKey, optionsValue) {
+ opt[optionsKey] = optionsValue;
+ });
+ if (tagName === "img") {
+ (function() {
+ var oldTargetSrc = target.src;
+ renderImageToDataURL(self.srcImage, self.blob, opt, doSquash).then(function(dataUri) {
+ target.src = dataUri;
+ oldTargetSrc === target.src && target.onload();
+ });
+ })();
+ } else if (tagName === "canvas") {
+ renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);
+ }
+ if (typeof this.onrender === "function") {
+ this.onrender(target);
+ }
+ };
+ qq.MegaPixImage = MegaPixImage;
+ })();
+ qq.ImageGenerator = function(log) {
+ "use strict";
+ function isImg(el) {
+ return el.tagName.toLowerCase() === "img";
+ }
+ function isCanvas(el) {
+ return el.tagName.toLowerCase() === "canvas";
+ }
+ function isImgCorsSupported() {
+ return new Image().crossOrigin !== undefined;
+ }
+ function isCanvasSupported() {
+ var canvas = document.createElement("canvas");
+ return canvas.getContext && canvas.getContext("2d");
+ }
+ function determineMimeOfFileName(nameWithPath) {
+ var pathSegments = nameWithPath.split("/"), name = pathSegments[pathSegments.length - 1].split("?")[0], extension = qq.getExtension(name);
+ extension = extension && extension.toLowerCase();
+ switch (extension) {
+ case "jpeg":
+ case "jpg":
+ return "image/jpeg";
+
+ case "png":
+ return "image/png";
+
+ case "bmp":
+ return "image/bmp";
+
+ case "gif":
+ return "image/gif";
+
+ case "tiff":
+ case "tif":
+ return "image/tiff";
+ }
+ }
+ function isCrossOrigin(url) {
+ var targetAnchor = document.createElement("a"), targetProtocol, targetHostname, targetPort;
+ targetAnchor.href = url;
+ targetProtocol = targetAnchor.protocol;
+ targetPort = targetAnchor.port;
+ targetHostname = targetAnchor.hostname;
+ if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {
+ return true;
+ }
+ if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {
+ return true;
+ }
+ if (targetPort !== window.location.port && !qq.ie()) {
+ return true;
+ }
+ return false;
+ }
+ function registerImgLoadListeners(img, promise) {
+ img.onload = function() {
+ img.onload = null;
+ img.onerror = null;
+ promise.success(img);
+ };
+ img.onerror = function() {
+ img.onload = null;
+ img.onerror = null;
+ log("Problem drawing thumbnail!", "error");
+ promise.failure(img, "Problem drawing thumbnail!");
+ };
+ }
+ function registerCanvasDrawImageListener(canvas, promise) {
+ canvas.qqImageRendered = function() {
+ promise.success(canvas);
+ };
+ }
+ function registerThumbnailRenderedListener(imgOrCanvas, promise) {
+ var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);
+ if (isImg(imgOrCanvas)) {
+ registerImgLoadListeners(imgOrCanvas, promise);
+ } else if (isCanvas(imgOrCanvas)) {
+ registerCanvasDrawImageListener(imgOrCanvas, promise);
+ } else {
+ promise.failure(imgOrCanvas);
+ log(qq.format("Element container of type {} is not supported!", imgOrCanvas.tagName), "error");
+ }
+ return registered;
+ }
+ function draw(fileOrBlob, container, options) {
+ var drawPreview = new qq.Promise(), identifier = new qq.Identify(fileOrBlob, log), maxSize = options.maxSize, orient = options.orient == null ? true : options.orient, megapixErrorHandler = function() {
+ container.onerror = null;
+ container.onload = null;
+ log("Could not render preview, file may be too large!", "error");
+ drawPreview.failure(container, "Browser cannot render image!");
+ };
+ identifier.isPreviewable().then(function(mime) {
+ var dummyExif = {
+ parse: function() {
+ return new qq.Promise().success();
+ }
+ }, exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif, mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);
+ if (registerThumbnailRenderedListener(container, drawPreview)) {
+ exif.parse().then(function(exif) {
+ var orientation = exif && exif.Orientation;
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ orientation: orientation,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ }, function(failureMsg) {
+ log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", failureMsg));
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ });
+ }
+ }, function() {
+ log("Not previewable");
+ drawPreview.failure(container, "Not previewable");
+ });
+ return drawPreview;
+ }
+ function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {
+ var tempImg = new Image(), tempImgRender = new qq.Promise();
+ registerThumbnailRenderedListener(tempImg, tempImgRender);
+ if (isCrossOrigin(url)) {
+ tempImg.crossOrigin = "anonymous";
+ }
+ tempImg.src = url;
+ tempImgRender.then(function rendered() {
+ registerThumbnailRenderedListener(canvasOrImg, draw);
+ var mpImg = new qq.MegaPixImage(tempImg);
+ mpImg.render(canvasOrImg, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: determineMimeOfFileName(url),
+ resize: customResizeFunction
+ });
+ }, draw.failure);
+ }
+ function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {
+ registerThumbnailRenderedListener(img, draw);
+ qq(img).css({
+ maxWidth: maxSize + "px",
+ maxHeight: maxSize + "px"
+ });
+ img.src = url;
+ }
+ function drawFromUrl(url, container, options) {
+ var draw = new qq.Promise(), scale = options.scale, maxSize = scale ? options.maxSize : null;
+ if (scale && isImg(container)) {
+ if (isCanvasSupported()) {
+ if (isCrossOrigin(url) && !isImgCorsSupported()) {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ } else {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ }
+ } else {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ }
+ } else if (isCanvas(container)) {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ } else if (registerThumbnailRenderedListener(container, draw)) {
+ container.src = url;
+ }
+ return draw;
+ }
+ qq.extend(this, {
+ generate: function(fileBlobOrUrl, container, options) {
+ if (qq.isString(fileBlobOrUrl)) {
+ log("Attempting to update thumbnail based on server response.");
+ return drawFromUrl(fileBlobOrUrl, container, options || {});
+ } else {
+ log("Attempting to draw client-side image preview.");
+ return draw(fileBlobOrUrl, container, options || {});
+ }
+ }
+ });
+ this._testing = {};
+ this._testing.isImg = isImg;
+ this._testing.isCanvas = isCanvas;
+ this._testing.isCrossOrigin = isCrossOrigin;
+ this._testing.determineMimeOfFileName = determineMimeOfFileName;
+ };
+ qq.Exif = function(fileOrBlob, log) {
+ "use strict";
+ var TAG_IDS = [ 274 ], TAG_INFO = {
+ 274: {
+ name: "Orientation",
+ bytes: 2
+ }
+ };
+ function parseLittleEndian(hex) {
+ var result = 0, pow = 0;
+ while (hex.length > 0) {
+ result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);
+ hex = hex.substring(2, hex.length);
+ pow += 8;
+ }
+ return result;
+ }
+ function seekToApp1(offset, promise) {
+ var theOffset = offset, thePromise = promise;
+ if (theOffset === undefined) {
+ theOffset = 2;
+ thePromise = new qq.Promise();
+ }
+ qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {
+ var match = /^ffe([0-9])/.exec(hex), segmentLength;
+ if (match) {
+ if (match[1] !== "1") {
+ segmentLength = parseInt(hex.slice(4, 8), 16);
+ seekToApp1(theOffset + segmentLength + 2, thePromise);
+ } else {
+ thePromise.success(theOffset);
+ }
+ } else {
+ thePromise.failure("No EXIF header to be found!");
+ }
+ });
+ return thePromise;
+ }
+ function getApp1Offset() {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {
+ if (hex.indexOf("ffd8") !== 0) {
+ promise.failure("Not a valid JPEG!");
+ } else {
+ seekToApp1().then(function(offset) {
+ promise.success(offset);
+ }, function(error) {
+ promise.failure(error);
+ });
+ }
+ });
+ return promise;
+ }
+ function isLittleEndian(app1Start) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {
+ promise.success(hex === "4949");
+ });
+ return promise;
+ }
+ function getDirEntryCount(app1Start, littleEndian) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {
+ if (littleEndian) {
+ return promise.success(parseLittleEndian(hex));
+ } else {
+ promise.success(parseInt(hex, 16));
+ }
+ });
+ return promise;
+ }
+ function getIfd(app1Start, dirEntries) {
+ var offset = app1Start + 20, bytes = dirEntries * 12;
+ return qq.readBlobToHex(fileOrBlob, offset, bytes);
+ }
+ function getDirEntries(ifdHex) {
+ var entries = [], offset = 0;
+ while (offset + 24 <= ifdHex.length) {
+ entries.push(ifdHex.slice(offset, offset + 24));
+ offset += 24;
+ }
+ return entries;
+ }
+ function getTagValues(littleEndian, dirEntries) {
+ var TAG_VAL_OFFSET = 16, tagsToFind = qq.extend([], TAG_IDS), vals = {};
+ qq.each(dirEntries, function(idx, entry) {
+ var idHex = entry.slice(0, 4), id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16), tagsToFindIdx = tagsToFind.indexOf(id), tagValHex, tagName, tagValLength;
+ if (tagsToFindIdx >= 0) {
+ tagName = TAG_INFO[id].name;
+ tagValLength = TAG_INFO[id].bytes;
+ tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + tagValLength * 2);
+ vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);
+ tagsToFind.splice(tagsToFindIdx, 1);
+ }
+ if (tagsToFind.length === 0) {
+ return false;
+ }
+ });
+ return vals;
+ }
+ qq.extend(this, {
+ parse: function() {
+ var parser = new qq.Promise(), onParseFailure = function(message) {
+ log(qq.format("EXIF header parse failed: '{}' ", message));
+ parser.failure(message);
+ };
+ getApp1Offset().then(function(app1Offset) {
+ log(qq.format("Moving forward with EXIF header parsing for '{}'", fileOrBlob.name === undefined ? "blob" : fileOrBlob.name));
+ isLittleEndian(app1Offset).then(function(littleEndian) {
+ log(qq.format("EXIF Byte order is {} endian", littleEndian ? "little" : "big"));
+ getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {
+ log(qq.format("Found {} APP1 directory entries", dirEntryCount));
+ getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {
+ var dirEntries = getDirEntries(ifdHex), tagValues = getTagValues(littleEndian, dirEntries);
+ log("Successfully parsed some EXIF tags");
+ parser.success(tagValues);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ return parser;
+ }
+ });
+ this._testing = {};
+ this._testing.parseLittleEndian = parseLittleEndian;
+ };
+ qq.Identify = function(fileOrBlob, log) {
+ "use strict";
+ function isIdentifiable(magicBytes, questionableBytes) {
+ var identifiable = false, magicBytesEntries = [].concat(magicBytes);
+ qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {
+ if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {
+ identifiable = true;
+ return false;
+ }
+ });
+ return identifiable;
+ }
+ qq.extend(this, {
+ isPreviewable: function() {
+ var self = this, identifier = new qq.Promise(), previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ log(qq.format("Attempting to determine if {} can be rendered in this browser", name));
+ log("First pass: check type attribute of blob object.");
+ if (this.isPreviewableSync()) {
+ log("Second pass: check for magic bytes in file header.");
+ qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {
+ qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {
+ if (isIdentifiable(bytes, hex)) {
+ if (mime !== "image/tiff" || qq.supportedFeatures.tiffPreviews) {
+ previewable = true;
+ identifier.success(mime);
+ }
+ return false;
+ }
+ });
+ log(qq.format("'{}' is {} able to be rendered in this browser", name, previewable ? "" : "NOT"));
+ if (!previewable) {
+ identifier.failure();
+ }
+ }, function() {
+ log("Error reading file w/ name '" + name + "'. Not able to be rendered in this browser.");
+ identifier.failure();
+ });
+ } else {
+ identifier.failure();
+ }
+ return identifier;
+ },
+ isPreviewableSync: function() {
+ var fileMime = fileOrBlob.type, isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0, previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ if (isRecognizedImage) {
+ if (fileMime === "image/tiff") {
+ previewable = qq.supportedFeatures.tiffPreviews;
+ } else {
+ previewable = true;
+ }
+ }
+ !previewable && log(name + " is not previewable in this browser per the blob's type attr");
+ return previewable;
+ }
+ });
+ };
+ qq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {
+ "image/jpeg": "ffd8ff",
+ "image/gif": "474946",
+ "image/png": "89504e",
+ "image/bmp": "424d",
+ "image/tiff": [ "49492a00", "4d4d002a" ]
+ };
+ qq.ImageValidation = function(blob, log) {
+ "use strict";
+ function hasNonZeroLimits(limits) {
+ var atLeastOne = false;
+ qq.each(limits, function(limit, value) {
+ if (value > 0) {
+ atLeastOne = true;
+ return false;
+ }
+ });
+ return atLeastOne;
+ }
+ function getWidthHeight() {
+ var sizeDetermination = new qq.Promise();
+ new qq.Identify(blob, log).isPreviewable().then(function() {
+ var image = new Image(), url = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (url) {
+ image.onerror = function() {
+ log("Cannot determine dimensions for image. May be too large.", "error");
+ sizeDetermination.failure();
+ };
+ image.onload = function() {
+ sizeDetermination.success({
+ width: this.width,
+ height: this.height
+ });
+ };
+ image.src = url.createObjectURL(blob);
+ } else {
+ log("No createObjectURL function available to generate image URL!", "error");
+ sizeDetermination.failure();
+ }
+ }, sizeDetermination.failure);
+ return sizeDetermination;
+ }
+ function getFailingLimit(limits, dimensions) {
+ var failingLimit;
+ qq.each(limits, function(limitName, limitValue) {
+ if (limitValue > 0) {
+ var limitMatcher = /(max|min)(Width|Height)/.exec(limitName), dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1), actualValue = dimensions[dimensionPropName];
+ switch (limitMatcher[1]) {
+ case "min":
+ if (actualValue < limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+
+ case "max":
+ if (actualValue > limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+ }
+ }
+ });
+ return failingLimit;
+ }
+ this.validate = function(limits) {
+ var validationEffort = new qq.Promise();
+ log("Attempting to validate image.");
+ if (hasNonZeroLimits(limits)) {
+ getWidthHeight().then(function(dimensions) {
+ var failingLimit = getFailingLimit(limits, dimensions);
+ if (failingLimit) {
+ validationEffort.failure(failingLimit);
+ } else {
+ validationEffort.success();
+ }
+ }, validationEffort.success);
+ } else {
+ validationEffort.success();
+ }
+ return validationEffort;
+ };
+ };
+ qq.Session = function(spec) {
+ "use strict";
+ var options = {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ cors: {},
+ addFileRecord: function(sessionData) {},
+ log: function(message, level) {}
+ };
+ qq.extend(options, spec, true);
+ function isJsonResponseValid(response) {
+ if (qq.isArray(response)) {
+ return true;
+ }
+ options.log("Session response is not an array.", "error");
+ }
+ function handleFileItems(fileItems, success, xhrOrXdr, promise) {
+ var someItemsIgnored = false;
+ success = success && isJsonResponseValid(fileItems);
+ if (success) {
+ qq.each(fileItems, function(idx, fileItem) {
+ if (fileItem.uuid == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid UUID - ignoring.", idx), "error");
+ } else if (fileItem.name == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid name - ignoring.", idx), "error");
+ } else {
+ try {
+ options.addFileRecord(fileItem);
+ return true;
+ } catch (err) {
+ someItemsIgnored = true;
+ options.log(err.message, "error");
+ }
+ }
+ return false;
+ });
+ }
+ promise[success && !someItemsIgnored ? "success" : "failure"](fileItems, xhrOrXdr);
+ }
+ this.refresh = function() {
+ var refreshEffort = new qq.Promise(), refreshCompleteCallback = function(response, success, xhrOrXdr) {
+ handleFileItems(response, success, xhrOrXdr, refreshEffort);
+ }, requesterOptions = qq.extend({}, options), requester = new qq.SessionAjaxRequester(qq.extend(requesterOptions, {
+ onComplete: refreshCompleteCallback
+ }));
+ requester.queryServer();
+ return refreshEffort;
+ };
+ };
+ qq.SessionAjaxRequester = function(spec) {
+ "use strict";
+ var requester, options = {
+ endpoint: null,
+ customHeaders: {},
+ params: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ onComplete: function(response, success, xhrOrXdr) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, spec);
+ function onComplete(id, xhrOrXdr, isError) {
+ var response = null;
+ if (xhrOrXdr.responseText != null) {
+ try {
+ response = qq.parseJson(xhrOrXdr.responseText);
+ } catch (err) {
+ options.log("Problem parsing session response: " + err.message, "error");
+ isError = true;
+ }
+ }
+ options.onComplete(response, !isError, xhrOrXdr);
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: onComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ queryServer: function() {
+ var params = qq.extend({}, options.params);
+ options.log("Session query request.");
+ requester.initTransport("sessionRefresh").withParams(params).withCacheBuster().send();
+ }
+ });
+ };
+ qq.Scaler = function(spec, log) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizer, includeOriginal = spec.sendOriginal, orient = spec.orient, defaultType = spec.defaultType, defaultQuality = spec.defaultQuality / 100, failedToScaleText = spec.failureText, includeExif = spec.includeExif, sizes = this._getSortedSizes(spec.sizes);
+ qq.extend(this, {
+ enabled: qq.supportedFeatures.scaling && sizes.length > 0,
+ getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {
+ var self = this, records = [], originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData, identifier = new qq.Identify(originalBlob, log);
+ if (identifier.isPreviewableSync()) {
+ qq.each(sizes, function(idx, sizeRecord) {
+ var outputType = self._determineOutputType({
+ defaultType: defaultType,
+ requestedType: sizeRecord.type,
+ refType: originalBlob.type
+ });
+ records.push({
+ uuid: qq.getUniqueId(),
+ name: self._getName(originalFileName, {
+ name: sizeRecord.name,
+ type: outputType,
+ refType: originalBlob.type
+ }),
+ blob: new qq.BlobProxy(originalBlob, qq.bind(self._generateScaledImage, self, {
+ customResizeFunction: customResizeFunction,
+ maxSize: sizeRecord.maxSize,
+ orient: orient,
+ type: outputType,
+ quality: defaultQuality,
+ failedText: failedToScaleText,
+ includeExif: includeExif,
+ log: log
+ }))
+ });
+ });
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: includeOriginal ? originalBlob : null
+ });
+ } else {
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: originalBlob
+ });
+ }
+ return records;
+ },
+ handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {
+ var self = this, buttonId = file.qqButtonId || file.blob && file.blob.qqButtonId, scaledIds = [], originalId = null, addFileToHandler = api.addFileToHandler, uploadData = api.uploadData, paramsStore = api.paramsStore, proxyGroupId = qq.getUniqueId();
+ qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {
+ var blobSize = record.size, id;
+ if (record.blob instanceof qq.BlobProxy) {
+ blobSize = -1;
+ }
+ id = uploadData.addFile({
+ uuid: record.uuid,
+ name: record.name,
+ size: blobSize,
+ batchId: batchId,
+ proxyGroupId: proxyGroupId
+ });
+ if (record.blob instanceof qq.BlobProxy) {
+ scaledIds.push(id);
+ } else {
+ originalId = id;
+ }
+ if (record.blob) {
+ addFileToHandler(id, record.blob);
+ fileList.push({
+ id: id,
+ file: record.blob
+ });
+ } else {
+ uploadData.setStatus(id, qq.status.REJECTED);
+ }
+ });
+ if (originalId !== null) {
+ qq.each(scaledIds, function(idx, scaledId) {
+ var params = {
+ qqparentuuid: uploadData.retrieve({
+ id: originalId
+ }).uuid,
+ qqparentsize: uploadData.retrieve({
+ id: originalId
+ }).size
+ };
+ params[uuidParamName] = uploadData.retrieve({
+ id: scaledId
+ }).uuid;
+ uploadData.setParentId(scaledId, originalId);
+ paramsStore.addReadOnly(scaledId, params);
+ });
+ if (scaledIds.length) {
+ (function() {
+ var param = {};
+ param[uuidParamName] = uploadData.retrieve({
+ id: originalId
+ }).uuid;
+ paramsStore.addReadOnly(originalId, param);
+ })();
+ }
+ }
+ }
+ });
+ };
+ qq.extend(qq.Scaler.prototype, {
+ scaleImage: function(id, specs, api) {
+ "use strict";
+ if (!qq.supportedFeatures.scaling) {
+ throw new qq.Error("Scaling is not supported in this browser!");
+ }
+ var scalingEffort = new qq.Promise(), log = api.log, file = api.getFile(id), uploadData = api.uploadData.retrieve({
+ id: id
+ }), name = uploadData && uploadData.name, uuid = uploadData && uploadData.uuid, scalingOptions = {
+ customResizer: specs.customResizer,
+ sendOriginal: false,
+ orient: specs.orient,
+ defaultType: specs.type || null,
+ defaultQuality: specs.quality,
+ failedToScaleText: "Unable to scale",
+ sizes: [ {
+ name: "",
+ maxSize: specs.maxSize
+ } ]
+ }, scaler = new qq.Scaler(scalingOptions, log);
+ if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {
+ scalingEffort.failure();
+ log("Could not generate requested scaled image for " + id + ". " + "Scaling is either not possible in this browser, or the file could not be located.", "error");
+ } else {
+ qq.bind(function() {
+ var record = scaler.getFileRecords(uuid, name, file)[0];
+ if (record && record.blob instanceof qq.BlobProxy) {
+ record.blob.create().then(scalingEffort.success, scalingEffort.failure);
+ } else {
+ log(id + " is not a scalable image!", "error");
+ scalingEffort.failure();
+ }
+ }, this)();
+ }
+ return scalingEffort;
+ },
+ _determineOutputType: function(spec) {
+ "use strict";
+ var requestedType = spec.requestedType, defaultType = spec.defaultType, referenceType = spec.refType;
+ if (!defaultType && !requestedType) {
+ if (referenceType !== "image/jpeg") {
+ return "image/png";
+ }
+ return referenceType;
+ }
+ if (!requestedType) {
+ return defaultType;
+ }
+ if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {
+ if (requestedType === "image/tiff") {
+ return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;
+ }
+ return requestedType;
+ }
+ return defaultType;
+ },
+ _getName: function(originalName, scaledVersionProperties) {
+ "use strict";
+ var startOfExt = originalName.lastIndexOf("."), versionType = scaledVersionProperties.type || "image/png", referenceType = scaledVersionProperties.refType, scaledName = "", scaledExt = qq.getExtension(originalName), nameAppendage = "";
+ if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {
+ nameAppendage = " (" + scaledVersionProperties.name + ")";
+ }
+ if (startOfExt >= 0) {
+ scaledName = originalName.substr(0, startOfExt);
+ if (referenceType !== versionType) {
+ scaledExt = versionType.split("/")[1];
+ }
+ scaledName += nameAppendage + "." + scaledExt;
+ } else {
+ scaledName = originalName + nameAppendage;
+ }
+ return scaledName;
+ },
+ _getSortedSizes: function(sizes) {
+ "use strict";
+ sizes = qq.extend([], sizes);
+ return sizes.sort(function(a, b) {
+ if (a.maxSize > b.maxSize) {
+ return 1;
+ }
+ if (a.maxSize < b.maxSize) {
+ return -1;
+ }
+ return 0;
+ });
+ },
+ _generateScaledImage: function(spec, sourceFile) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizeFunction, log = spec.log, maxSize = spec.maxSize, orient = spec.orient, type = spec.type, quality = spec.quality, failedText = spec.failedText, includeExif = spec.includeExif && sourceFile.type === "image/jpeg" && type === "image/jpeg", scalingEffort = new qq.Promise(), imageGenerator = new qq.ImageGenerator(log), canvas = document.createElement("canvas");
+ log("Attempting to generate scaled version for " + sourceFile.name);
+ imageGenerator.generate(sourceFile, canvas, {
+ maxSize: maxSize,
+ orient: orient,
+ customResizeFunction: customResizeFunction
+ }).then(function() {
+ var scaledImageDataUri = canvas.toDataURL(type, quality), signalSuccess = function() {
+ log("Success generating scaled version for " + sourceFile.name);
+ var blob = qq.dataUriToBlob(scaledImageDataUri);
+ scalingEffort.success(blob);
+ };
+ if (includeExif) {
+ self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {
+ scaledImageDataUri = scaledImageDataUriWithExif;
+ signalSuccess();
+ }, function() {
+ log("Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.", "error");
+ signalSuccess();
+ });
+ } else {
+ signalSuccess();
+ }
+ }, function() {
+ log("Failed attempt to generate scaled version for " + sourceFile.name, "error");
+ scalingEffort.failure(failedText);
+ });
+ return scalingEffort;
+ },
+ _insertExifHeader: function(originalImage, scaledImageDataUri, log) {
+ "use strict";
+ var reader = new FileReader(), insertionEffort = new qq.Promise(), originalImageDataUri = "";
+ reader.onload = function() {
+ originalImageDataUri = reader.result;
+ insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));
+ };
+ reader.onerror = function() {
+ log("Problem reading " + originalImage.name + " during attempt to transfer EXIF data to scaled version.", "error");
+ insertionEffort.failure();
+ };
+ reader.readAsDataURL(originalImage);
+ return insertionEffort;
+ },
+ _dataUriToBlob: function(dataUri) {
+ "use strict";
+ var byteString, mimeString, arrayBuffer, intArray;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return this._createBlob(arrayBuffer, mimeString);
+ },
+ _createBlob: function(data, mime) {
+ "use strict";
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }
+ });
+ qq.ExifRestorer = function() {
+ var ExifRestorer = {};
+ ExifRestorer.KEY_STR = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + "ghijklmnopqrstuv" + "wxyz0123456789+/" + "=";
+ ExifRestorer.encode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0;
+ do {
+ chr1 = input[i++];
+ chr2 = input[i++];
+ chr3 = input[i++];
+ enc1 = chr1 >> 2;
+ enc2 = (chr1 & 3) << 4 | chr2 >> 4;
+ enc3 = (chr2 & 15) << 2 | chr3 >> 6;
+ enc4 = chr3 & 63;
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+ output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4);
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return output;
+ };
+ ExifRestorer.restore = function(origFileBase64, resizedFileBase64) {
+ var expectedBase64Header = "data:image/jpeg;base64,";
+ if (!origFileBase64.match(expectedBase64Header)) {
+ return resizedFileBase64;
+ }
+ var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, ""));
+ var segments = this.slice2Segments(rawImage);
+ var image = this.exifManipulation(resizedFileBase64, segments);
+ return expectedBase64Header + this.encode64(image);
+ };
+ ExifRestorer.exifManipulation = function(resizedFileBase64, segments) {
+ var exifArray = this.getExifArray(segments), newImageArray = this.insertExif(resizedFileBase64, exifArray), aBuffer = new Uint8Array(newImageArray);
+ return aBuffer;
+ };
+ ExifRestorer.getExifArray = function(segments) {
+ var seg;
+ for (var x = 0; x < segments.length; x++) {
+ seg = segments[x];
+ if (seg[0] == 255 & seg[1] == 225) {
+ return seg;
+ }
+ }
+ return [];
+ };
+ ExifRestorer.insertExif = function(resizedFileBase64, exifArray) {
+ var imageData = resizedFileBase64.replace("data:image/jpeg;base64,", ""), buf = this.decode64(imageData), separatePoint = buf.indexOf(255, 3), mae = buf.slice(0, separatePoint), ato = buf.slice(separatePoint), array = mae;
+ array = array.concat(exifArray);
+ array = array.concat(ato);
+ return array;
+ };
+ ExifRestorer.slice2Segments = function(rawImageArray) {
+ var head = 0, segments = [];
+ while (1) {
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218) {
+ break;
+ }
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216) {
+ head += 2;
+ } else {
+ var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3], endPoint = head + length + 2, seg = rawImageArray.slice(head, endPoint);
+ segments.push(seg);
+ head = endPoint;
+ }
+ if (head > rawImageArray.length) {
+ break;
+ }
+ }
+ return segments;
+ };
+ ExifRestorer.decode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0, buf = [];
+ var base64test = /[^A-Za-z0-9\+\/\=]/g;
+ if (base64test.exec(input)) {
+ throw new Error("There were invalid base64 characters in the input text. " + "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");
+ }
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+ do {
+ enc1 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc2 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc3 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc4 = this.KEY_STR.indexOf(input.charAt(i++));
+ chr1 = enc1 << 2 | enc2 >> 4;
+ chr2 = (enc2 & 15) << 4 | enc3 >> 2;
+ chr3 = (enc3 & 3) << 6 | enc4;
+ buf.push(chr1);
+ if (enc3 != 64) {
+ buf.push(chr2);
+ }
+ if (enc4 != 64) {
+ buf.push(chr3);
+ }
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return buf;
+ };
+ return ExifRestorer;
+ }();
+ qq.TotalProgress = function(callback, getSize) {
+ "use strict";
+ var perFileProgress = {}, totalLoaded = 0, totalSize = 0, lastLoadedSent = -1, lastTotalSent = -1, callbackProxy = function(loaded, total) {
+ if (loaded !== lastLoadedSent || total !== lastTotalSent) {
+ callback(loaded, total);
+ }
+ lastLoadedSent = loaded;
+ lastTotalSent = total;
+ }, noRetryableFiles = function(failed, retryable) {
+ var none = true;
+ qq.each(failed, function(idx, failedId) {
+ if (qq.indexOf(retryable, failedId) >= 0) {
+ none = false;
+ return false;
+ }
+ });
+ return none;
+ }, onCancel = function(id) {
+ updateTotalProgress(id, -1, -1);
+ delete perFileProgress[id];
+ }, onAllComplete = function(successful, failed, retryable) {
+ if (failed.length === 0 || noRetryableFiles(failed, retryable)) {
+ callbackProxy(totalSize, totalSize);
+ this.reset();
+ }
+ }, onNew = function(id) {
+ var size = getSize(id);
+ if (size > 0) {
+ updateTotalProgress(id, 0, size);
+ perFileProgress[id] = {
+ loaded: 0,
+ total: size
+ };
+ }
+ }, updateTotalProgress = function(id, newLoaded, newTotal) {
+ var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0, oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;
+ if (newLoaded === -1 && newTotal === -1) {
+ totalLoaded -= oldLoaded;
+ totalSize -= oldTotal;
+ } else {
+ if (newLoaded) {
+ totalLoaded += newLoaded - oldLoaded;
+ }
+ if (newTotal) {
+ totalSize += newTotal - oldTotal;
+ }
+ }
+ callbackProxy(totalLoaded, totalSize);
+ };
+ qq.extend(this, {
+ onAllComplete: onAllComplete,
+ onStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {
+ onCancel(id);
+ } else if (newStatus === qq.status.SUBMITTING) {
+ onNew(id);
+ }
+ },
+ onIndividualProgress: function(id, loaded, total) {
+ updateTotalProgress(id, loaded, total);
+ perFileProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onNewSize: function(id) {
+ onNew(id);
+ },
+ reset: function() {
+ perFileProgress = {};
+ totalLoaded = 0;
+ totalSize = 0;
+ }
+ });
+ };
+ qq.PasteSupport = function(o) {
+ "use strict";
+ var options, detachPasteHandler;
+ options = {
+ targetElement: null,
+ callbacks: {
+ log: function(message, level) {},
+ pasteReceived: function(blob) {}
+ }
+ };
+ function isImage(item) {
+ return item.type && item.type.indexOf("image/") === 0;
+ }
+ function registerPasteHandler() {
+ detachPasteHandler = qq(options.targetElement).attach("paste", function(event) {
+ var clipboardData = event.clipboardData;
+ if (clipboardData) {
+ qq.each(clipboardData.items, function(idx, item) {
+ if (isImage(item)) {
+ var blob = item.getAsFile();
+ options.callbacks.pasteReceived(blob);
+ }
+ });
+ }
+ });
+ }
+ function unregisterPasteHandler() {
+ if (detachPasteHandler) {
+ detachPasteHandler();
+ }
+ }
+ qq.extend(options, o);
+ registerPasteHandler();
+ qq.extend(this, {
+ reset: function() {
+ unregisterPasteHandler();
+ }
+ });
+ };
+ qq.FormSupport = function(options, startUpload, log) {
+ "use strict";
+ var self = this, interceptSubmit = options.interceptSubmit, formEl = options.element, autoUpload = options.autoUpload;
+ qq.extend(this, {
+ newEndpoint: null,
+ newAutoUpload: autoUpload,
+ attachedToForm: false,
+ getFormInputsAsObject: function() {
+ if (formEl == null) {
+ return null;
+ }
+ return self._form2Obj(formEl);
+ }
+ });
+ function determineNewEndpoint(formEl) {
+ if (formEl.getAttribute("action")) {
+ self.newEndpoint = formEl.getAttribute("action");
+ }
+ }
+ function validateForm(formEl, nativeSubmit) {
+ if (formEl.checkValidity && !formEl.checkValidity()) {
+ log("Form did not pass validation checks - will not upload.", "error");
+ nativeSubmit();
+ } else {
+ return true;
+ }
+ }
+ function maybeUploadOnSubmit(formEl) {
+ var nativeSubmit = formEl.submit;
+ qq(formEl).attach("submit", function(event) {
+ event = event || window.event;
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
+ validateForm(formEl, nativeSubmit) && startUpload();
+ });
+ formEl.submit = function() {
+ validateForm(formEl, nativeSubmit) && startUpload();
+ };
+ }
+ function determineFormEl(formEl) {
+ if (formEl) {
+ if (qq.isString(formEl)) {
+ formEl = document.getElementById(formEl);
+ }
+ if (formEl) {
+ log("Attaching to form element.");
+ determineNewEndpoint(formEl);
+ interceptSubmit && maybeUploadOnSubmit(formEl);
+ }
+ }
+ return formEl;
+ }
+ formEl = determineFormEl(formEl);
+ this.attachedToForm = !!formEl;
+ };
+ qq.extend(qq.FormSupport.prototype, {
+ _form2Obj: function(form) {
+ "use strict";
+ var obj = {}, notIrrelevantType = function(type) {
+ var irrelevantTypes = [ "button", "image", "reset", "submit" ];
+ return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;
+ }, radioOrCheckbox = function(type) {
+ return qq.indexOf([ "checkbox", "radio" ], type.toLowerCase()) >= 0;
+ }, ignoreValue = function(el) {
+ if (radioOrCheckbox(el.type) && !el.checked) {
+ return true;
+ }
+ return el.disabled && el.type.toLowerCase() !== "hidden";
+ }, selectValue = function(select) {
+ var value = null;
+ qq.each(qq(select).children(), function(idx, child) {
+ if (child.tagName.toLowerCase() === "option" && child.selected) {
+ value = child.value;
+ return false;
+ }
+ });
+ return value;
+ };
+ qq.each(form.elements, function(idx, el) {
+ if ((qq.isInput(el, true) || el.tagName.toLowerCase() === "textarea") && notIrrelevantType(el.type) && !ignoreValue(el)) {
+ obj[el.name] = el.value;
+ } else if (el.tagName.toLowerCase() === "select" && !ignoreValue(el)) {
+ var value = selectValue(el);
+ if (value !== null) {
+ obj[el.name] = value;
+ }
+ }
+ });
+ return obj;
+ }
+ });
+ qq.azure = qq.azure || {};
+ qq.azure.util = qq.azure.util || function() {
+ "use strict";
+ return {
+ AZURE_PARAM_PREFIX: "x-ms-meta-",
+ _paramNameMatchesAzureParameter: function(name) {
+ switch (name) {
+ case "Cache-Control":
+ case "Content-Disposition":
+ case "Content-Encoding":
+ case "Content-MD5":
+ case "x-ms-blob-content-encoding":
+ case "x-ms-blob-content-disposition":
+ case "x-ms-blob-content-md5":
+ case "x-ms-blob-cache-control":
+ return true;
+
+ default:
+ return false;
+ }
+ },
+ _getPrefixedParamName: function(name) {
+ if (qq.azure.util._paramNameMatchesAzureParameter(name)) {
+ return name;
+ } else {
+ return qq.azure.util.AZURE_PARAM_PREFIX + name;
+ }
+ },
+ getParamsAsHeaders: function(params) {
+ var headers = {};
+ qq.each(params, function(name, val) {
+ var headerName = qq.azure.util._getPrefixedParamName(name), value = null;
+ if (qq.isFunction(val)) {
+ value = String(val());
+ } else if (qq.isObject(val)) {
+ qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));
+ } else {
+ value = String(val);
+ }
+ if (value !== null) {
+ if (qq.azure.util._paramNameMatchesAzureParameter(name)) {
+ headers[headerName] = value;
+ } else {
+ headers[headerName] = encodeURIComponent(value);
+ }
+ }
+ });
+ return headers;
+ },
+ parseAzureError: function(responseText, log) {
+ var domParser = new DOMParser(), responseDoc = domParser.parseFromString(responseText, "application/xml"), errorTag = responseDoc.getElementsByTagName("Error")[0], errorDetails = {}, codeTag, messageTag;
+ log("Received error response: " + responseText, "error");
+ if (errorTag) {
+ messageTag = errorTag.getElementsByTagName("Message")[0];
+ if (messageTag) {
+ errorDetails.message = messageTag.textContent;
+ }
+ codeTag = errorTag.getElementsByTagName("Code")[0];
+ if (codeTag) {
+ errorDetails.code = codeTag.textContent;
+ }
+ log("Parsed Azure error: " + JSON.stringify(errorDetails), "error");
+ return errorDetails;
+ }
+ }
+ };
+ }();
+ (function() {
+ "use strict";
+ qq.nonTraditionalBasePublicApi = {
+ setUploadSuccessParams: function(params, id) {
+ this._uploadSuccessParamsStore.set(params, id);
+ },
+ setUploadSuccessEndpoint: function(endpoint, id) {
+ this._uploadSuccessEndpointStore.set(endpoint, id);
+ }
+ };
+ qq.nonTraditionalBasePrivateApi = {
+ _onComplete: function(id, name, result, xhr) {
+ var success = result.success ? true : false, self = this, onCompleteArgs = arguments, successEndpoint = this._uploadSuccessEndpointStore.get(id), successCustomHeaders = this._options.uploadSuccess.customHeaders, successMethod = this._options.uploadSuccess.method, cors = this._options.cors, promise = new qq.Promise(), uploadSuccessParams = this._uploadSuccessParamsStore.get(id), fileParams = this._paramsStore.get(id), onSuccessFromServer = function(successRequestResult) {
+ delete self._failedSuccessRequestCallbacks[id];
+ qq.extend(result, successRequestResult);
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.success(successRequestResult);
+ }, onFailureFromServer = function(successRequestResult) {
+ var callback = submitSuccessRequest;
+ qq.extend(result, successRequestResult);
+ if (result && result.reset) {
+ callback = null;
+ }
+ if (!callback) {
+ delete self._failedSuccessRequestCallbacks[id];
+ } else {
+ self._failedSuccessRequestCallbacks[id] = callback;
+ }
+ if (!self._onAutoRetry(id, name, result, xhr, callback)) {
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.failure(successRequestResult);
+ }
+ }, submitSuccessRequest, successAjaxRequester;
+ if (success && successEndpoint) {
+ successAjaxRequester = new qq.UploadSuccessAjaxRequester({
+ endpoint: successEndpoint,
+ method: successMethod,
+ customHeaders: successCustomHeaders,
+ cors: cors,
+ log: qq.bind(this.log, this)
+ });
+ qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);
+ fileParams && qq.extend(uploadSuccessParams, fileParams, true);
+ submitSuccessRequest = qq.bind(function() {
+ successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams).then(onSuccessFromServer, onFailureFromServer);
+ }, self);
+ submitSuccessRequest();
+ return promise;
+ }
+ return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);
+ },
+ _manualRetry: function(id) {
+ var successRequestCallback = this._failedSuccessRequestCallbacks[id];
+ return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.azure.FineUploaderBasic = function(o) {
+ if (!qq.supportedFeatures.ajaxUploading) {
+ throw new qq.Error("Uploading directly to Azure is not possible in this browser.");
+ }
+ var options = {
+ signature: {
+ endpoint: null,
+ customHeaders: {}
+ },
+ blobProperties: {
+ name: "uuid"
+ },
+ uploadSuccess: {
+ endpoint: null,
+ method: "POST",
+ params: {},
+ customHeaders: {}
+ },
+ chunking: {
+ partSize: 4e6,
+ minFileSize: 4000001
+ }
+ };
+ qq.extend(options, o, true);
+ qq.FineUploaderBasic.call(this, options);
+ this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);
+ this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);
+ this._failedSuccessRequestCallbacks = {};
+ this._cannedBlobNames = {};
+ };
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, {
+ getBlobName: function(id) {
+ if (this._cannedBlobNames[id] == null) {
+ return this._handler.getThirdPartyFileId(id);
+ }
+ return this._cannedBlobNames[id];
+ },
+ _getEndpointSpecificParams: function(id) {
+ return {
+ blob: this.getBlobName(id),
+ uuid: this.getUuid(id),
+ name: this.getName(id),
+ container: this._endpointStore.get(id)
+ };
+ },
+ _createUploadHandler: function() {
+ return qq.FineUploaderBasic.prototype._createUploadHandler.call(this, {
+ signature: this._options.signature,
+ onGetBlobName: qq.bind(this._determineBlobName, this),
+ deleteBlob: qq.bind(this._deleteBlob, this, true)
+ }, "azure");
+ },
+ _determineBlobName: function(id) {
+ var self = this, blobNameOptionValue = this._options.blobProperties.name, uuid = this.getUuid(id), filename = this.getName(id), fileExtension = qq.getExtension(filename), blobNameToUse = uuid;
+ if (qq.isString(blobNameOptionValue)) {
+ switch (blobNameOptionValue) {
+ case "uuid":
+ if (fileExtension !== undefined) {
+ blobNameToUse += "." + fileExtension;
+ }
+ return new qq.Promise().success(blobNameToUse);
+
+ case "filename":
+ return new qq.Promise().success(filename);
+
+ default:
+ return new qq.Promise.failure("Invalid blobName option value - " + blobNameOptionValue);
+ }
+ } else {
+ return blobNameOptionValue.call(this, id);
+ }
+ },
+ _addCannedFile: function(sessionData) {
+ var id;
+ if (sessionData.blobName == null) {
+ throw new qq.Error("Did not find blob name property in server session response. This is required!");
+ } else {
+ id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);
+ this._cannedBlobNames[id] = sessionData.blobName;
+ }
+ return id;
+ },
+ _deleteBlob: function(relatedToCancel, id) {
+ var self = this, deleteBlobSasUri = {}, blobUriStore = {
+ get: function(id) {
+ return self._endpointStore.get(id) + "/" + self.getBlobName(id);
+ }
+ }, deleteFileEndpointStore = {
+ get: function(id) {
+ return deleteBlobSasUri[id];
+ }
+ }, getSasSuccess = function(id, sasUri) {
+ deleteBlobSasUri[id] = sasUri;
+ deleteBlob.send(id);
+ }, getSasFailure = function(id, reason, xhr) {
+ if (relatedToCancel) {
+ self.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS", "error");
+ qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));
+ } else {
+ self._onDeleteComplete(id, xhr, true);
+ self._options.callbacks.onDeleteComplete(id, xhr, true);
+ }
+ }, deleteBlob = new qq.azure.DeleteBlob({
+ endpointStore: deleteFileEndpointStore,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ delete deleteBlobSasUri[id];
+ if (isError) {
+ if (relatedToCancel) {
+ self.log("Will cancel upload, but failed to remove uncommitted parts from Azure.", "error");
+ } else {
+ qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));
+ }
+ }
+ if (relatedToCancel) {
+ qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));
+ self.log("Deleted uncommitted blob chunks for " + id);
+ } else {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ }
+ }), getSas = new qq.azure.GetSas({
+ cors: this._options.cors,
+ customHeaders: this._options.signature.customHeaders,
+ endpointStore: {
+ get: function() {
+ return self._options.signature.endpoint;
+ }
+ },
+ restRequestVerb: deleteBlob.method,
+ log: qq.bind(self.log, self)
+ });
+ getSas.request(id, blobUriStore.get(id)).then(qq.bind(getSasSuccess, self, id), qq.bind(getSasFailure, self, id));
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return {
+ sendDelete: function(id, uuid) {
+ self._deleteBlob(false, id);
+ }
+ };
+ }
+ });
+ })();
+ qq.azure.XhrUploadHandler = function(spec, proxy) {
+ "use strict";
+ var handler = this, log = proxy.log, cors = spec.cors, endpointStore = spec.endpointStore, paramsStore = spec.paramsStore, signature = spec.signature, filenameParam = spec.filenameParam, minFileSizeForChunking = spec.chunking.minFileSize, deleteBlob = spec.deleteBlob, onGetBlobName = spec.onGetBlobName, getName = proxy.getName, getSize = proxy.getSize, getBlobMetadata = function(id) {
+ var params = paramsStore.get(id);
+ params[filenameParam] = getName(id);
+ return params;
+ }, api = {
+ putBlob: new qq.azure.PutBlob({
+ getBlobMetadata: getBlobMetadata,
+ log: log
+ }),
+ putBlock: new qq.azure.PutBlock({
+ log: log
+ }),
+ putBlockList: new qq.azure.PutBlockList({
+ getBlobMetadata: getBlobMetadata,
+ log: log
+ }),
+ getSasForPutBlobOrBlock: new qq.azure.GetSas({
+ cors: cors,
+ customHeaders: signature.customHeaders,
+ endpointStore: {
+ get: function() {
+ return signature.endpoint;
+ }
+ },
+ log: log,
+ restRequestVerb: "PUT"
+ })
+ };
+ function combineChunks(id) {
+ var promise = new qq.Promise();
+ getSignedUrl(id).then(function(sasUri) {
+ var mimeType = handler._getMimeType(id), blockIdEntries = handler._getPersistableData(id).blockIdEntries;
+ api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {
+ handler._registerXhr(id, null, xhr, api.putBlockList);
+ }).then(function(xhr) {
+ log("Success combining chunks for id " + id);
+ promise.success({}, xhr);
+ }, function(xhr) {
+ log("Attempt to combine chunks failed for id " + id, "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ }
+ function determineBlobUrl(id) {
+ var containerUrl = endpointStore.get(id), promise = new qq.Promise(), getBlobNameSuccess = function(blobName) {
+ handler._setThirdPartyFileId(id, blobName);
+ promise.success(containerUrl + "/" + blobName);
+ }, getBlobNameFailure = function(reason) {
+ promise.failure(reason);
+ };
+ onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);
+ return promise;
+ }
+ function getSignedUrl(id, optChunkIdx) {
+ var getSasId = optChunkIdx == null ? id : id + "." + optChunkIdx, promise = new qq.Promise(), getSasSuccess = function(sasUri) {
+ log("GET SAS request succeeded.");
+ promise.success(sasUri);
+ }, getSasFailure = function(reason, getSasXhr) {
+ log("GET SAS request failed: " + reason, "error");
+ promise.failure({
+ error: "Problem communicating with local server"
+ }, getSasXhr);
+ }, determineBlobUrlSuccess = function(blobUrl) {
+ api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(getSasSuccess, getSasFailure);
+ }, determineBlobUrlFailure = function(reason) {
+ log(qq.format("Failed to determine blob name for ID {} - {}", id, reason), "error");
+ promise.failure({
+ error: reason
+ });
+ };
+ determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);
+ return promise;
+ }
+ function handleFailure(xhr, promise) {
+ var azureError = qq.azure.util.parseAzureError(xhr.responseText, log), errorMsg = "Problem sending file to Azure";
+ promise.failure({
+ error: errorMsg,
+ azureError: azureError && azureError.message,
+ reset: xhr.status === 403
+ });
+ }
+ qq.extend(this, {
+ uploadChunk: function(id, chunkIdx) {
+ var promise = new qq.Promise();
+ getSignedUrl(id, chunkIdx).then(function(sasUri) {
+ var xhr = handler._createXhr(id, chunkIdx), chunkData = handler._getChunkData(id, chunkIdx);
+ handler._registerProgressHandler(id, chunkIdx, chunkData.size);
+ handler._registerXhr(id, chunkIdx, xhr, api.putBlock);
+ api.putBlock.upload(id + "." + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(function(blockIdEntry) {
+ if (!handler._getPersistableData(id).blockIdEntries) {
+ handler._getPersistableData(id).blockIdEntries = [];
+ }
+ handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);
+ log("Put Block call succeeded for " + id);
+ promise.success({}, xhr);
+ }, function() {
+ log(qq.format("Put Block call failed for ID {} on part {}", id, chunkIdx), "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ },
+ uploadFile: function(id) {
+ var promise = new qq.Promise(), fileOrBlob = handler.getFile(id);
+ getSignedUrl(id).then(function(sasUri) {
+ var xhr = handler._createXhr(id);
+ handler._registerProgressHandler(id);
+ api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(function() {
+ log("Put Blob call succeeded for " + id);
+ promise.success({}, xhr);
+ }, function() {
+ log("Put Blob call failed for " + id, "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ }
+ });
+ qq.extend(this, new qq.XhrUploadHandler({
+ options: qq.extend({
+ namespace: "azure"
+ }, spec),
+ proxy: qq.extend({
+ getEndpoint: spec.endpointStore.get
+ }, proxy)
+ }));
+ qq.override(this, function(super_) {
+ return {
+ expunge: function(id) {
+ var relatedToCancel = handler._wasCanceled(id), chunkingData = handler._getPersistableData(id), blockIdEntries = chunkingData && chunkingData.blockIdEntries || [];
+ if (relatedToCancel && blockIdEntries.length > 0) {
+ deleteBlob(id);
+ }
+ super_.expunge(id);
+ },
+ finalizeChunks: function(id) {
+ return combineChunks(id);
+ },
+ _shouldChunkThisFile: function(id) {
+ var maybePossible = super_._shouldChunkThisFile(id);
+ return maybePossible && getSize(id) >= minFileSizeForChunking;
+ }
+ };
+ });
+ };
+ qq.azure.GetSas = function(o) {
+ "use strict";
+ var requester, options = {
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ customHeaders: {},
+ restRequestVerb: "PUT",
+ endpointStore: null,
+ log: function(str, level) {}
+ }, requestPromises = {};
+ qq.extend(options, o);
+ function sasResponseReceived(id, xhr, isError) {
+ var promise = requestPromises[id];
+ if (isError) {
+ promise.failure("Received response code " + xhr.status, xhr);
+ } else {
+ if (xhr.responseText.length) {
+ promise.success(xhr.responseText);
+ } else {
+ promise.failure("Empty response.", xhr);
+ }
+ }
+ delete requestPromises[id];
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ successfulResponseCodes: {
+ GET: [ 200 ]
+ },
+ contentType: null,
+ customHeaders: options.customHeaders,
+ endpointStore: options.endpointStore,
+ cors: options.cors,
+ log: options.log,
+ onComplete: sasResponseReceived
+ }));
+ qq.extend(this, {
+ request: function(id, blobUri) {
+ var requestPromise = new qq.Promise(), restVerb = options.restRequestVerb;
+ options.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.", restVerb, id));
+ requestPromises[id] = requestPromise;
+ requester.initTransport(id).withParams({
+ bloburi: blobUri,
+ _method: restVerb
+ }).withCacheBuster().send();
+ return requestPromise;
+ }
+ });
+ };
+ qq.UploadSuccessAjaxRequester = function(o) {
+ "use strict";
+ var requester, pendingRequests = [], options = {
+ method: "POST",
+ endpoint: null,
+ maxConnections: 3,
+ customHeaders: {},
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {}
+ };
+ qq.extend(options, o);
+ function handleSuccessResponse(id, xhrOrXdr, isError) {
+ var promise = pendingRequests[id], responseJson = xhrOrXdr.responseText, successIndicator = {
+ success: true
+ }, failureIndicator = {
+ success: false
+ }, parsedResponse;
+ delete pendingRequests[id];
+ options.log(qq.format("Received the following response body to an upload success request for id {}: {}", id, responseJson));
+ try {
+ parsedResponse = qq.parseJson(responseJson);
+ if (isError || parsedResponse && (parsedResponse.error || parsedResponse.success === false)) {
+ options.log("Upload success request was rejected by the server.", "error");
+ promise.failure(qq.extend(parsedResponse, failureIndicator));
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(qq.extend(parsedResponse, successIndicator));
+ }
+ } catch (error) {
+ if (isError) {
+ options.log(qq.format("Your server indicated failure in its upload success request response for id {}!", id), "error");
+ promise.failure(failureIndicator);
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(successIndicator);
+ }
+ }
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ method: options.method,
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ paramsStore: options.paramsStore,
+ maxConnections: options.maxConnections,
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: handleSuccessResponse,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendSuccessRequest: function(id, spec) {
+ var promise = new qq.Promise();
+ options.log("Submitting upload success request/notification for " + id);
+ requester.initTransport(id).withParams(spec).send();
+ pendingRequests[id] = promise;
+ return promise;
+ }
+ });
+ };
+ qq.azure.DeleteBlob = function(o) {
+ "use strict";
+ var requester, method = "DELETE", options = {
+ endpointStore: {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhr, isError) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 202 ];
+ return codes;
+ }(),
+ contentType: null,
+ endpointStore: options.endpointStore,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete
+ }));
+ qq.extend(this, {
+ method: method,
+ send: function(id) {
+ options.log("Submitting Delete Blob request for " + id);
+ return requester.initTransport(id).send();
+ }
+ });
+ };
+ qq.azure.PutBlob = function(o) {
+ "use strict";
+ var requester, method = "PUT", options = {
+ getBlobMetadata: function(id) {},
+ log: function(str, level) {}
+ }, endpoints = {}, promises = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ contentType: null,
+ customHeaders: function(id) {
+ var params = options.getBlobMetadata(id), headers = qq.azure.util.getParamsAsHeaders(params);
+ headers["x-ms-blob-type"] = "BlockBlob";
+ return headers;
+ },
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id];
+ delete endpoints[id];
+ delete promises[id];
+ if (isError) {
+ promise.failure();
+ } else {
+ promise.success();
+ }
+ }
+ }));
+ qq.extend(this, {
+ method: method,
+ upload: function(id, xhr, url, file) {
+ var promise = new qq.Promise();
+ options.log("Submitting Put Blob request for " + id);
+ promises[id] = promise;
+ endpoints[id] = url;
+ requester.initTransport(id).withPayload(file).withHeaders({
+ "Content-Type": file.type
+ }).send(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.azure.PutBlock = function(o) {
+ "use strict";
+ var requester, method = "PUT", blockIdEntries = {}, promises = {}, options = {
+ log: function(str, level) {}
+ }, endpoints = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ contentType: null,
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id], blockIdEntry = blockIdEntries[id];
+ delete endpoints[id];
+ delete promises[id];
+ delete blockIdEntries[id];
+ if (isError) {
+ promise.failure();
+ } else {
+ promise.success(blockIdEntry);
+ }
+ }
+ }));
+ function createBlockId(partNum) {
+ var digits = 5, zeros = new Array(digits + 1).join("0"), paddedPartNum = (zeros + partNum).slice(-digits);
+ return btoa(paddedPartNum);
+ }
+ qq.extend(this, {
+ method: method,
+ upload: function(id, xhr, sasUri, partNum, blob) {
+ var promise = new qq.Promise(), blockId = createBlockId(partNum);
+ promises[id] = promise;
+ options.log(qq.format("Submitting Put Block request for {} = part {}", id, partNum));
+ endpoints[id] = qq.format("{}&comp=block&blockid={}", sasUri, encodeURIComponent(blockId));
+ blockIdEntries[id] = {
+ part: partNum,
+ id: blockId
+ };
+ requester.initTransport(id).withPayload(blob).send(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.azure.PutBlockList = function(o) {
+ "use strict";
+ var requester, method = "PUT", promises = {}, options = {
+ getBlobMetadata: function(id) {},
+ log: function(str, level) {}
+ }, endpoints = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ customHeaders: function(id) {
+ var params = options.getBlobMetadata(id);
+ return qq.azure.util.getParamsAsHeaders(params);
+ },
+ contentType: "text/plain",
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onSend: function() {},
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id];
+ delete endpoints[id];
+ delete promises[id];
+ if (isError) {
+ promise.failure(xhr);
+ } else {
+ promise.success(xhr);
+ }
+ }
+ }));
+ function createRequestBody(blockIdEntries) {
+ var doc = document.implementation.createDocument(null, "BlockList", null);
+ blockIdEntries.sort(function(a, b) {
+ return a.part - b.part;
+ });
+ qq.each(blockIdEntries, function(idx, blockIdEntry) {
+ var latestEl = doc.createElement("Latest"), latestTextEl = doc.createTextNode(blockIdEntry.id);
+ latestEl.appendChild(latestTextEl);
+ qq(doc).children()[0].appendChild(latestEl);
+ });
+ return new XMLSerializer().serializeToString(doc);
+ }
+ qq.extend(this, {
+ method: method,
+ send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {
+ var promise = new qq.Promise(), blockIdsXml = createRequestBody(blockIdEntries), xhr;
+ promises[id] = promise;
+ options.log(qq.format("Submitting Put Block List request for {}", id));
+ endpoints[id] = qq.format("{}&comp=blocklist", sasUri);
+ xhr = requester.initTransport(id).withPayload(blockIdsXml).withHeaders({
+ "x-ms-blob-content-type": fileMimeType
+ }).send();
+ registerXhrCallback(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.DragAndDrop = function(o) {
+ "use strict";
+ var options, HIDE_ZONES_EVENT_NAME = "qq-hidezones", HIDE_BEFORE_ENTER_ATTR = "qq-hide-dropzone", uploadDropZones = [], droppedFiles = [], disposeSupport = new qq.DisposeSupport();
+ options = {
+ dropZoneElements: [],
+ allowMultipleItems: true,
+ classes: {
+ dropActive: null
+ },
+ callbacks: new qq.DragAndDrop.callbacks()
+ };
+ qq.extend(options, o, true);
+ function uploadDroppedFiles(files, uploadDropZone) {
+ var filesAsArray = Array.prototype.slice.call(files);
+ options.callbacks.dropLog("Grabbed " + files.length + " dropped files.");
+ uploadDropZone.dropDisabled(false);
+ options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());
+ }
+ function traverseFileTree(entry) {
+ var parseEntryPromise = new qq.Promise();
+ if (entry.isFile) {
+ entry.file(function(file) {
+ var name = entry.name, fullPath = entry.fullPath, indexOfNameInFullPath = fullPath.indexOf(name);
+ fullPath = fullPath.substr(0, indexOfNameInFullPath);
+ if (fullPath.charAt(0) === "/") {
+ fullPath = fullPath.substr(1);
+ }
+ file.qqPath = fullPath;
+ droppedFiles.push(file);
+ parseEntryPromise.success();
+ }, function(fileError) {
+ options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error");
+ parseEntryPromise.failure();
+ });
+ } else if (entry.isDirectory) {
+ getFilesInDirectory(entry).then(function allEntriesRead(entries) {
+ var entriesLeft = entries.length;
+ qq.each(entries, function(idx, entry) {
+ traverseFileTree(entry).done(function() {
+ entriesLeft -= 1;
+ if (entriesLeft === 0) {
+ parseEntryPromise.success();
+ }
+ });
+ });
+ if (!entries.length) {
+ parseEntryPromise.success();
+ }
+ }, function readFailure(fileError) {
+ options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error");
+ parseEntryPromise.failure();
+ });
+ }
+ return parseEntryPromise;
+ }
+ function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {
+ var promise = existingPromise || new qq.Promise(), dirReader = reader || entry.createReader();
+ dirReader.readEntries(function readSuccess(entries) {
+ var newEntries = accumEntries ? accumEntries.concat(entries) : entries;
+ if (entries.length) {
+ setTimeout(function() {
+ getFilesInDirectory(entry, dirReader, newEntries, promise);
+ }, 0);
+ } else {
+ promise.success(newEntries);
+ }
+ }, promise.failure);
+ return promise;
+ }
+ function handleDataTransfer(dataTransfer, uploadDropZone) {
+ var pendingFolderPromises = [], handleDataTransferPromise = new qq.Promise();
+ options.callbacks.processingDroppedFiles();
+ uploadDropZone.dropDisabled(true);
+ if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {
+ options.callbacks.processingDroppedFilesComplete([]);
+ options.callbacks.dropError("tooManyFilesError", "");
+ uploadDropZone.dropDisabled(false);
+ handleDataTransferPromise.failure();
+ } else {
+ droppedFiles = [];
+ if (qq.isFolderDropSupported(dataTransfer)) {
+ qq.each(dataTransfer.items, function(idx, item) {
+ var entry = item.webkitGetAsEntry();
+ if (entry) {
+ if (entry.isFile) {
+ droppedFiles.push(item.getAsFile());
+ } else {
+ pendingFolderPromises.push(traverseFileTree(entry).done(function() {
+ pendingFolderPromises.pop();
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }));
+ }
+ }
+ });
+ } else {
+ droppedFiles = dataTransfer.files;
+ }
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }
+ return handleDataTransferPromise;
+ }
+ function setupDropzone(dropArea) {
+ var dropZone = new qq.UploadDropZone({
+ HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,
+ element: dropArea,
+ onEnter: function(e) {
+ qq(dropArea).addClass(options.classes.dropActive);
+ e.stopPropagation();
+ },
+ onLeaveNotDescendants: function(e) {
+ qq(dropArea).removeClass(options.classes.dropActive);
+ },
+ onDrop: function(e) {
+ handleDataTransfer(e.dataTransfer, dropZone).then(function() {
+ uploadDroppedFiles(droppedFiles, dropZone);
+ }, function() {
+ options.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.", "error");
+ });
+ }
+ });
+ disposeSupport.addDisposer(function() {
+ dropZone.dispose();
+ });
+ qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();
+ uploadDropZones.push(dropZone);
+ return dropZone;
+ }
+ function isFileDrag(dragEvent) {
+ var fileDrag;
+ qq.each(dragEvent.dataTransfer.types, function(key, val) {
+ if (val === "Files") {
+ fileDrag = true;
+ return false;
+ }
+ });
+ return fileDrag;
+ }
+ function leavingDocumentOut(e) {
+ if (qq.firefox()) {
+ return !e.relatedTarget;
+ }
+ if (qq.safari()) {
+ return e.x < 0 || e.y < 0;
+ }
+ return e.x === 0 && e.y === 0;
+ }
+ function setupDragDrop() {
+ var dropZones = options.dropZoneElements, maybeHideDropZones = function() {
+ setTimeout(function() {
+ qq.each(dropZones, function(idx, dropZone) {
+ qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();
+ qq(dropZone).removeClass(options.classes.dropActive);
+ });
+ }, 10);
+ };
+ qq.each(dropZones, function(idx, dropZone) {
+ var uploadDropZone = setupDropzone(dropZone);
+ if (dropZones.length && qq.supportedFeatures.fileDrop) {
+ disposeSupport.attach(document, "dragenter", function(e) {
+ if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {
+ qq.each(dropZones, function(idx, dropZone) {
+ if (dropZone instanceof HTMLElement && qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {
+ qq(dropZone).css({
+ display: "block"
+ });
+ }
+ });
+ }
+ });
+ }
+ });
+ disposeSupport.attach(document, "dragleave", function(e) {
+ if (leavingDocumentOut(e)) {
+ maybeHideDropZones();
+ }
+ });
+ disposeSupport.attach(qq(document).children()[0], "mouseenter", function(e) {
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, "drop", function(e) {
+ e.preventDefault();
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);
+ }
+ setupDragDrop();
+ qq.extend(this, {
+ setupExtraDropzone: function(element) {
+ options.dropZoneElements.push(element);
+ setupDropzone(element);
+ },
+ removeDropzone: function(element) {
+ var i, dzs = options.dropZoneElements;
+ for (i in dzs) {
+ if (dzs[i] === element) {
+ return dzs.splice(i, 1);
+ }
+ }
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ qq.each(uploadDropZones, function(idx, dropZone) {
+ dropZone.dispose();
+ });
+ }
+ });
+ };
+ qq.DragAndDrop.callbacks = function() {
+ "use strict";
+ return {
+ processingDroppedFiles: function() {},
+ processingDroppedFilesComplete: function(files, targetEl) {},
+ dropError: function(code, errorSpecifics) {
+ qq.log("Drag & drop error code '" + code + " with these specifics: '" + errorSpecifics + "'", "error");
+ },
+ dropLog: function(message, level) {
+ qq.log(message, level);
+ }
+ };
+ };
+ qq.UploadDropZone = function(o) {
+ "use strict";
+ var disposeSupport = new qq.DisposeSupport(), options, element, preventDrop, dropOutsideDisabled;
+ options = {
+ element: null,
+ onEnter: function(e) {},
+ onLeave: function(e) {},
+ onLeaveNotDescendants: function(e) {},
+ onDrop: function(e) {}
+ };
+ qq.extend(options, o);
+ element = options.element;
+ function dragoverShouldBeCanceled() {
+ return qq.safari() || qq.firefox() && qq.windows();
+ }
+ function disableDropOutside(e) {
+ if (!dropOutsideDisabled) {
+ if (dragoverShouldBeCanceled) {
+ disposeSupport.attach(document, "dragover", function(e) {
+ e.preventDefault();
+ });
+ } else {
+ disposeSupport.attach(document, "dragover", function(e) {
+ if (e.dataTransfer) {
+ e.dataTransfer.dropEffect = "none";
+ e.preventDefault();
+ }
+ });
+ }
+ dropOutsideDisabled = true;
+ }
+ }
+ function isValidFileDrag(e) {
+ if (!qq.supportedFeatures.fileDrop) {
+ return false;
+ }
+ var effectTest, dt = e.dataTransfer, isSafari = qq.safari();
+ effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== "none";
+ return dt && effectTest && (dt.files || !isSafari && dt.types.contains && dt.types.contains("Files"));
+ }
+ function isOrSetDropDisabled(isDisabled) {
+ if (isDisabled !== undefined) {
+ preventDrop = isDisabled;
+ }
+ return preventDrop;
+ }
+ function triggerHidezonesEvent() {
+ var hideZonesEvent;
+ function triggerUsingOldApi() {
+ hideZonesEvent = document.createEvent("Event");
+ hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);
+ }
+ if (window.CustomEvent) {
+ try {
+ hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);
+ } catch (err) {
+ triggerUsingOldApi();
+ }
+ } else {
+ triggerUsingOldApi();
+ }
+ document.dispatchEvent(hideZonesEvent);
+ }
+ function attachEvents() {
+ disposeSupport.attach(element, "dragover", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;
+ if (effect === "move" || effect === "linkMove") {
+ e.dataTransfer.dropEffect = "move";
+ } else {
+ e.dataTransfer.dropEffect = "copy";
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ disposeSupport.attach(element, "dragenter", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onEnter(e);
+ }
+ });
+ disposeSupport.attach(element, "dragleave", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onLeave(e);
+ var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
+ if (qq(this).contains(relatedTarget)) {
+ return;
+ }
+ options.onLeaveNotDescendants(e);
+ });
+ disposeSupport.attach(element, "drop", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ options.onDrop(e);
+ triggerHidezonesEvent();
+ }
+ });
+ }
+ disableDropOutside();
+ attachEvents();
+ qq.extend(this, {
+ dropDisabled: function(isDisabled) {
+ return isOrSetDropDisabled(isDisabled);
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ },
+ getElement: function() {
+ return element;
+ }
+ });
+ };
+ (function() {
+ "use strict";
+ qq.uiPublicApi = {
+ addInitialFiles: function(cannedFileList) {
+ this._parent.prototype.addInitialFiles.apply(this, arguments);
+ this._templating.addCacheToDom();
+ },
+ clearStoredFiles: function() {
+ this._parent.prototype.clearStoredFiles.apply(this, arguments);
+ this._templating.clearFiles();
+ },
+ addExtraDropzone: function(element) {
+ this._dnd && this._dnd.setupExtraDropzone(element);
+ },
+ removeExtraDropzone: function(element) {
+ if (this._dnd) {
+ return this._dnd.removeDropzone(element);
+ }
+ },
+ getItemByFileId: function(id) {
+ if (!this._templating.isHiddenForever(id)) {
+ return this._templating.getFileContainer(id);
+ }
+ },
+ reset: function() {
+ this._parent.prototype.reset.apply(this, arguments);
+ this._templating.reset();
+ if (!this._options.button && this._templating.getButton()) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._templating.getButton(),
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ if (this._dnd) {
+ this._dnd.dispose();
+ this._dnd = this._setupDragAndDrop();
+ }
+ this._totalFilesInBatch = 0;
+ this._filesInBatchAddedToUi = 0;
+ this._setupClickAndEditEventHandlers();
+ },
+ setName: function(id, newName) {
+ var formattedFilename = this._options.formatFileName(newName);
+ this._parent.prototype.setName.apply(this, arguments);
+ this._templating.updateFilename(id, formattedFilename);
+ },
+ pauseUpload: function(id) {
+ var paused = this._parent.prototype.pauseUpload.apply(this, arguments);
+ paused && this._templating.uploadPaused(id);
+ return paused;
+ },
+ continueUpload: function(id) {
+ var continued = this._parent.prototype.continueUpload.apply(this, arguments);
+ continued && this._templating.uploadContinued(id);
+ return continued;
+ },
+ getId: function(fileContainerOrChildEl) {
+ return this._templating.getFileId(fileContainerOrChildEl);
+ },
+ getDropTarget: function(fileId) {
+ var file = this.getFile(fileId);
+ return file.qqDropTarget;
+ }
+ };
+ qq.uiPrivateApi = {
+ _getButton: function(buttonId) {
+ var button = this._parent.prototype._getButton.apply(this, arguments);
+ if (!button) {
+ if (buttonId === this._defaultButtonId) {
+ button = this._templating.getButton();
+ }
+ }
+ return button;
+ },
+ _removeFileItem: function(fileId) {
+ this._templating.removeFile(fileId);
+ },
+ _setupClickAndEditEventHandlers: function() {
+ this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();
+ this._focusinEventSupported = !qq.firefox();
+ if (this._isEditFilenameEnabled()) {
+ this._filenameClickHandler = this._bindFilenameClickEvent();
+ this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();
+ this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();
+ }
+ },
+ _setupDragAndDrop: function() {
+ var self = this, dropZoneElements = this._options.dragAndDrop.extraDropzones, templating = this._templating, defaultDropZone = templating.getDropZone();
+ defaultDropZone && dropZoneElements.push(defaultDropZone);
+ return new qq.DragAndDrop({
+ dropZoneElements: dropZoneElements,
+ allowMultipleItems: this._options.multiple,
+ classes: {
+ dropActive: this._options.classes.dropActive
+ },
+ callbacks: {
+ processingDroppedFiles: function() {
+ templating.showDropProcessing();
+ },
+ processingDroppedFilesComplete: function(files, targetEl) {
+ templating.hideDropProcessing();
+ qq.each(files, function(idx, file) {
+ file.qqDropTarget = targetEl;
+ });
+ if (files.length) {
+ self.addFiles(files, null, null);
+ }
+ },
+ dropError: function(code, errorData) {
+ self._itemError(code, errorData);
+ },
+ dropLog: function(message, level) {
+ self.log(message, level);
+ }
+ }
+ });
+ },
+ _bindFileButtonsClickEvent: function() {
+ var self = this;
+ return new qq.FileButtonsClickHandler({
+ templating: this._templating,
+ log: function(message, lvl) {
+ self.log(message, lvl);
+ },
+ onDeleteFile: function(fileId) {
+ self.deleteFile(fileId);
+ },
+ onCancel: function(fileId) {
+ self.cancel(fileId);
+ },
+ onRetry: function(fileId) {
+ self.retry(fileId);
+ },
+ onPause: function(fileId) {
+ self.pauseUpload(fileId);
+ },
+ onContinue: function(fileId) {
+ self.continueUpload(fileId);
+ },
+ onGetName: function(fileId) {
+ return self.getName(fileId);
+ }
+ });
+ },
+ _isEditFilenameEnabled: function() {
+ return this._templating.isEditFilenamePossible() && !this._options.autoUpload && qq.FilenameClickHandler && qq.FilenameInputFocusHandler && qq.FilenameInputFocusHandler;
+ },
+ _filenameEditHandler: function() {
+ var self = this, templating = this._templating;
+ return {
+ templating: templating,
+ log: function(message, lvl) {
+ self.log(message, lvl);
+ },
+ onGetUploadStatus: function(fileId) {
+ return self.getUploads({
+ id: fileId
+ }).status;
+ },
+ onGetName: function(fileId) {
+ return self.getName(fileId);
+ },
+ onSetName: function(id, newName) {
+ self.setName(id, newName);
+ },
+ onEditingStatusChange: function(id, isEditing) {
+ var qqInput = qq(templating.getEditInput(id)), qqFileContainer = qq(templating.getFileContainer(id));
+ if (isEditing) {
+ qqInput.addClass("qq-editing");
+ templating.hideFilename(id);
+ templating.hideEditIcon(id);
+ } else {
+ qqInput.removeClass("qq-editing");
+ templating.showFilename(id);
+ templating.showEditIcon(id);
+ }
+ qqFileContainer.addClass("qq-temp").removeClass("qq-temp");
+ }
+ };
+ },
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ this._parent.prototype._onUploadStatusChange.apply(this, arguments);
+ if (this._isEditFilenameEnabled()) {
+ if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {
+ this._templating.markFilenameEditable(id);
+ this._templating.hideEditIcon(id);
+ }
+ }
+ if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {
+ this._templating.hideRetry(id);
+ this._templating.setStatusText(id);
+ qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);
+ } else if (newStatus === qq.status.UPLOAD_FAILED) {
+ this._templating.hidePause(id);
+ }
+ },
+ _bindFilenameInputFocusInEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameInputFocusInHandler(spec);
+ },
+ _bindFilenameInputFocusEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameInputFocusHandler(spec);
+ },
+ _bindFilenameClickEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameClickHandler(spec);
+ },
+ _storeForLater: function(id) {
+ this._parent.prototype._storeForLater.apply(this, arguments);
+ this._templating.hideSpinner(id);
+ },
+ _onAllComplete: function(successful, failed) {
+ this._parent.prototype._onAllComplete.apply(this, arguments);
+ this._templating.resetTotalProgress();
+ },
+ _onSubmit: function(id, name) {
+ var file = this.getFile(id);
+ if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {
+ this._paramsStore.addReadOnly(id, {
+ qqpath: file.qqPath
+ });
+ }
+ this._parent.prototype._onSubmit.apply(this, arguments);
+ this._addToList(id, name);
+ },
+ _onSubmitted: function(id) {
+ if (this._isEditFilenameEnabled()) {
+ this._templating.markFilenameEditable(id);
+ this._templating.showEditIcon(id);
+ if (!this._focusinEventSupported) {
+ this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));
+ }
+ }
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._parent.prototype._onProgress.apply(this, arguments);
+ this._templating.updateProgress(id, loaded, total);
+ if (total === 0 || Math.round(loaded / total * 100) === 100) {
+ this._templating.hideCancel(id);
+ this._templating.hidePause(id);
+ this._templating.hideProgress(id);
+ this._templating.setStatusText(id, this._options.text.waitingForResponse);
+ this._displayFileSize(id);
+ } else {
+ this._displayFileSize(id, loaded, total);
+ }
+ },
+ _onTotalProgress: function(loaded, total) {
+ this._parent.prototype._onTotalProgress.apply(this, arguments);
+ this._templating.updateTotalProgress(loaded, total);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments), templating = this._templating, fileContainer = templating.getFileContainer(id), self = this;
+ function completeUpload(result) {
+ if (!fileContainer) {
+ return;
+ }
+ templating.setStatusText(id);
+ qq(fileContainer).removeClass(self._classes.retrying);
+ templating.hideProgress(id);
+ if (self.getUploads({
+ id: id
+ }).status !== qq.status.UPLOAD_FAILED) {
+ templating.hideCancel(id);
+ }
+ templating.hideSpinner(id);
+ if (result.success) {
+ self._markFileAsSuccessful(id);
+ } else {
+ qq(fileContainer).addClass(self._classes.fail);
+ templating.showCancel(id);
+ if (templating.isRetryPossible() && !self._preventRetries[id]) {
+ qq(fileContainer).addClass(self._classes.retryable);
+ templating.showRetry(id);
+ }
+ self._controlFailureTextDisplay(id, result);
+ }
+ }
+ if (parentRetVal instanceof qq.Promise) {
+ parentRetVal.done(function(newResult) {
+ completeUpload(newResult);
+ });
+ } else {
+ completeUpload(result);
+ }
+ return parentRetVal;
+ },
+ _markFileAsSuccessful: function(id) {
+ var templating = this._templating;
+ if (this._isDeletePossible()) {
+ templating.showDeleteButton(id);
+ }
+ qq(templating.getFileContainer(id)).addClass(this._classes.success);
+ this._maybeUpdateThumbnail(id);
+ },
+ _onUploadPrep: function(id) {
+ this._parent.prototype._onUploadPrep.apply(this, arguments);
+ this._templating.showSpinner(id);
+ },
+ _onUpload: function(id, name) {
+ var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);
+ this._templating.showSpinner(id);
+ return parentRetVal;
+ },
+ _onUploadChunk: function(id, chunkData) {
+ this._parent.prototype._onUploadChunk.apply(this, arguments);
+ if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {
+ this._templating.allowPause(id);
+ }
+ },
+ _onCancel: function(id, name) {
+ this._parent.prototype._onCancel.apply(this, arguments);
+ this._removeFileItem(id);
+ if (this._getNotFinished() === 0) {
+ this._templating.resetTotalProgress();
+ }
+ },
+ _onBeforeAutoRetry: function(id) {
+ var retryNumForDisplay, maxAuto, retryNote;
+ this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);
+ this._showCancelLink(id);
+ if (this._options.retry.showAutoRetryNote) {
+ retryNumForDisplay = this._autoRetries[id];
+ maxAuto = this._options.retry.maxAutoAttempts;
+ retryNote = this._options.retry.autoRetryNote.replace(/\{retryNum\}/g, retryNumForDisplay);
+ retryNote = retryNote.replace(/\{maxAuto\}/g, maxAuto);
+ this._templating.setStatusText(id, retryNote);
+ qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);
+ }
+ },
+ _onBeforeManualRetry: function(id) {
+ if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {
+ this._templating.resetProgress(id);
+ qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);
+ this._templating.setStatusText(id);
+ this._templating.showSpinner(id);
+ this._showCancelLink(id);
+ return true;
+ } else {
+ qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);
+ this._templating.showRetry(id);
+ return false;
+ }
+ },
+ _onSubmitDelete: function(id) {
+ var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);
+ this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);
+ },
+ _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {
+ if (this._options.deleteFile.forceConfirm) {
+ this._showDeleteConfirm.apply(this, arguments);
+ } else {
+ this._sendDeleteRequest.apply(this, arguments);
+ }
+ },
+ _onDeleteComplete: function(id, xhr, isError) {
+ this._parent.prototype._onDeleteComplete.apply(this, arguments);
+ this._templating.hideSpinner(id);
+ if (isError) {
+ this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);
+ this._templating.showDeleteButton(id);
+ } else {
+ this._removeFileItem(id);
+ }
+ },
+ _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {
+ this._templating.hideDeleteButton(id);
+ this._templating.showSpinner(id);
+ this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);
+ this._deleteHandler.sendDelete.apply(this, arguments);
+ },
+ _showDeleteConfirm: function(id, uuid, mandatedParams) {
+ var fileName = this.getName(id), confirmMessage = this._options.deleteFile.confirmMessage.replace(/\{filename\}/g, fileName), uuid = this.getUuid(id), deleteRequestArgs = arguments, self = this, retVal;
+ retVal = this._options.showConfirm(confirmMessage);
+ if (qq.isGenericPromise(retVal)) {
+ retVal.then(function() {
+ self._sendDeleteRequest.apply(self, deleteRequestArgs);
+ });
+ } else if (retVal !== false) {
+ self._sendDeleteRequest.apply(self, deleteRequestArgs);
+ }
+ },
+ _addToList: function(id, name, canned) {
+ var prependData, prependIndex = 0, dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled, record;
+ if (this._options.display.prependFiles) {
+ if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {
+ prependIndex = this._filesInBatchAddedToUi - 1;
+ }
+ prependData = {
+ index: prependIndex
+ };
+ }
+ if (!canned) {
+ if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {
+ this._templating.disableCancel();
+ }
+ if (!this._options.multiple) {
+ record = this.getUploads({
+ id: id
+ });
+ this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;
+ if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {
+ this._handler.cancelAll();
+ this._clearList();
+ this._handledProxyGroup = null;
+ }
+ }
+ }
+ if (canned) {
+ this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);
+ this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);
+ } else {
+ this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);
+ this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);
+ }
+ this._filesInBatchAddedToUi += 1;
+ if (canned || this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading) {
+ this._displayFileSize(id);
+ }
+ },
+ _clearList: function() {
+ this._templating.clearFiles();
+ this.clearStoredFiles();
+ },
+ _displayFileSize: function(id, loadedSize, totalSize) {
+ var size = this.getSize(id), sizeForDisplay = this._formatSize(size);
+ if (size >= 0) {
+ if (loadedSize !== undefined && totalSize !== undefined) {
+ sizeForDisplay = this._formatProgress(loadedSize, totalSize);
+ }
+ this._templating.updateSize(id, sizeForDisplay);
+ }
+ },
+ _formatProgress: function(uploadedSize, totalSize) {
+ var message = this._options.text.formatProgress;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ r("{percent}", Math.round(uploadedSize / totalSize * 100));
+ r("{total_size}", this._formatSize(totalSize));
+ return message;
+ },
+ _controlFailureTextDisplay: function(id, response) {
+ var mode, responseProperty, failureReason;
+ mode = this._options.failedUploadTextDisplay.mode;
+ responseProperty = this._options.failedUploadTextDisplay.responseProperty;
+ if (mode === "custom") {
+ failureReason = response[responseProperty];
+ if (!failureReason) {
+ failureReason = this._options.text.failUpload;
+ }
+ this._templating.setStatusText(id, failureReason);
+ if (this._options.failedUploadTextDisplay.enableTooltip) {
+ this._showTooltip(id, failureReason);
+ }
+ } else if (mode === "default") {
+ this._templating.setStatusText(id, this._options.text.failUpload);
+ } else if (mode !== "none") {
+ this.log("failedUploadTextDisplay.mode value of '" + mode + "' is not valid", "warn");
+ }
+ },
+ _showTooltip: function(id, text) {
+ this._templating.getFileContainer(id).title = text;
+ },
+ _showCancelLink: function(id) {
+ if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {
+ this._templating.showCancel(id);
+ }
+ },
+ _itemError: function(code, name, item) {
+ var message = this._parent.prototype._itemError.apply(this, arguments);
+ this._options.showMessage(message);
+ },
+ _batchError: function(message) {
+ this._parent.prototype._batchError.apply(this, arguments);
+ this._options.showMessage(message);
+ },
+ _setupPastePrompt: function() {
+ var self = this;
+ this._options.callbacks.onPasteReceived = function() {
+ var message = self._options.paste.namePromptMessage, defaultVal = self._options.paste.defaultName;
+ return self._options.showPrompt(message, defaultVal);
+ };
+ },
+ _fileOrBlobRejected: function(id, name) {
+ this._totalFilesInBatch -= 1;
+ this._parent.prototype._fileOrBlobRejected.apply(this, arguments);
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ this._totalFilesInBatch = items.length;
+ this._filesInBatchAddedToUi = 0;
+ this._parent.prototype._prepareItemsForUpload.apply(this, arguments);
+ },
+ _maybeUpdateThumbnail: function(fileId) {
+ var thumbnailUrl = this._thumbnailUrls[fileId], fileStatus = this.getUploads({
+ id: fileId
+ }).status;
+ if (fileStatus !== qq.status.DELETED && (thumbnailUrl || this._options.thumbnails.placeholders.waitUntilResponse || !qq.supportedFeatures.imagePreviews)) {
+ this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);
+ }
+ },
+ _addCannedFile: function(sessionData) {
+ var id = this._parent.prototype._addCannedFile.apply(this, arguments);
+ this._addToList(id, this.getName(id), true);
+ this._templating.hideSpinner(id);
+ this._templating.hideCancel(id);
+ this._markFileAsSuccessful(id);
+ return id;
+ },
+ _setSize: function(id, newSize) {
+ this._parent.prototype._setSize.apply(this, arguments);
+ this._templating.updateSize(id, this._formatSize(newSize));
+ },
+ _sessionRequestComplete: function() {
+ this._templating.addCacheToDom();
+ this._parent.prototype._sessionRequestComplete.apply(this, arguments);
+ }
+ };
+ })();
+ qq.FineUploader = function(o, namespace) {
+ "use strict";
+ var self = this;
+ this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;
+ this._parent.apply(this, arguments);
+ qq.extend(this._options, {
+ element: null,
+ button: null,
+ listElement: null,
+ dragAndDrop: {
+ extraDropzones: [],
+ reportDirectoryPaths: false
+ },
+ text: {
+ formatProgress: "{percent}% of {total_size}",
+ failUpload: "Upload failed",
+ waitingForResponse: "Processing...",
+ paused: "Paused"
+ },
+ template: "qq-template",
+ classes: {
+ retrying: "qq-upload-retrying",
+ retryable: "qq-upload-retryable",
+ success: "qq-upload-success",
+ fail: "qq-upload-fail",
+ editable: "qq-editable",
+ hide: "qq-hide",
+ dropActive: "qq-upload-drop-area-active"
+ },
+ failedUploadTextDisplay: {
+ mode: "default",
+ responseProperty: "error",
+ enableTooltip: true
+ },
+ messages: {
+ tooManyFilesError: "You may only drop one file",
+ unsupportedBrowser: "Unrecoverable error - this browser does not permit file uploading of any kind."
+ },
+ retry: {
+ showAutoRetryNote: true,
+ autoRetryNote: "Retrying {retryNum}/{maxAuto}..."
+ },
+ deleteFile: {
+ forceConfirm: false,
+ confirmMessage: "Are you sure you want to delete {filename}?",
+ deletingStatusText: "Deleting...",
+ deletingFailedText: "Delete failed"
+ },
+ display: {
+ fileSizeOnSubmit: false,
+ prependFiles: false
+ },
+ paste: {
+ promptForName: false,
+ namePromptMessage: "Please name this image"
+ },
+ thumbnails: {
+ customResizer: null,
+ maxCount: 0,
+ placeholders: {
+ waitUntilResponse: false,
+ notAvailablePath: null,
+ waitingPath: null
+ },
+ timeBetweenThumbs: 750
+ },
+ scaling: {
+ hideScaled: false
+ },
+ showMessage: function(message) {
+ if (self._templating.hasDialog("alert")) {
+ return self._templating.showDialog("alert", message);
+ } else {
+ setTimeout(function() {
+ window.alert(message);
+ }, 0);
+ }
+ },
+ showConfirm: function(message) {
+ if (self._templating.hasDialog("confirm")) {
+ return self._templating.showDialog("confirm", message);
+ } else {
+ return window.confirm(message);
+ }
+ },
+ showPrompt: function(message, defaultValue) {
+ if (self._templating.hasDialog("prompt")) {
+ return self._templating.showDialog("prompt", message, defaultValue);
+ } else {
+ return window.prompt(message, defaultValue);
+ }
+ }
+ }, true);
+ qq.extend(this._options, o, true);
+ this._templating = new qq.Templating({
+ log: qq.bind(this.log, this),
+ templateIdOrEl: this._options.template,
+ containerEl: this._options.element,
+ fileContainerEl: this._options.listElement,
+ button: this._options.button,
+ imageGenerator: this._imageGenerator,
+ classes: {
+ hide: this._options.classes.hide,
+ editable: this._options.classes.editable
+ },
+ limits: {
+ maxThumbs: this._options.thumbnails.maxCount,
+ timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs
+ },
+ placeholders: {
+ waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,
+ thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,
+ waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath
+ },
+ text: this._options.text
+ });
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);
+ } else if (!qq.supportedFeatures.uploading || this._options.cors.expected && !qq.supportedFeatures.uploadCors) {
+ this._templating.renderFailure(this._options.messages.unsupportedBrowser);
+ } else {
+ this._wrapCallbacks();
+ this._templating.render();
+ this._classes = this._options.classes;
+ if (!this._options.button && this._templating.getButton()) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._templating.getButton(),
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._setupClickAndEditEventHandlers();
+ if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {
+ this._dnd = this._setupDragAndDrop();
+ }
+ if (this._options.paste.targetElement && this._options.paste.promptForName) {
+ if (qq.PasteSupport) {
+ this._setupPastePrompt();
+ } else {
+ this.log("Paste support module not found.", "error");
+ }
+ }
+ this._totalFilesInBatch = 0;
+ this._filesInBatchAddedToUi = 0;
+ }
+ };
+ qq.extend(qq.FineUploader.prototype, qq.basePublicApi);
+ qq.extend(qq.FineUploader.prototype, qq.basePrivateApi);
+ qq.extend(qq.FineUploader.prototype, qq.uiPublicApi);
+ qq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);
+ qq.Templating = function(spec) {
+ "use strict";
+ var FILE_ID_ATTR = "qq-file-id", FILE_CLASS_PREFIX = "qq-file-id-", THUMBNAIL_MAX_SIZE_ATTR = "qq-max-size", THUMBNAIL_SERVER_SCALE_ATTR = "qq-server-scale", HIDE_DROPZONE_ATTR = "qq-hide-dropzone", DROPZPONE_TEXT_ATTR = "qq-drop-area-text", IN_PROGRESS_CLASS = "qq-in-progress", HIDDEN_FOREVER_CLASS = "qq-hidden-forever", fileBatch = {
+ content: document.createDocumentFragment(),
+ map: {}
+ }, isCancelDisabled = false, generatedThumbnails = 0, thumbnailQueueMonitorRunning = false, thumbGenerationQueue = [], thumbnailMaxSize = -1, options = {
+ log: null,
+ limits: {
+ maxThumbs: 0,
+ timeBetweenThumbs: 750
+ },
+ templateIdOrEl: "qq-template",
+ containerEl: null,
+ fileContainerEl: null,
+ button: null,
+ imageGenerator: null,
+ classes: {
+ hide: "qq-hide",
+ editable: "qq-editable"
+ },
+ placeholders: {
+ waitUntilUpdate: false,
+ thumbnailNotAvailable: null,
+ waitingForThumbnail: null
+ },
+ text: {
+ paused: "Paused"
+ }
+ }, selectorClasses = {
+ button: "qq-upload-button-selector",
+ alertDialog: "qq-alert-dialog-selector",
+ dialogCancelButton: "qq-cancel-button-selector",
+ confirmDialog: "qq-confirm-dialog-selector",
+ dialogMessage: "qq-dialog-message-selector",
+ dialogOkButton: "qq-ok-button-selector",
+ promptDialog: "qq-prompt-dialog-selector",
+ uploader: "qq-uploader-selector",
+ drop: "qq-upload-drop-area-selector",
+ list: "qq-upload-list-selector",
+ progressBarContainer: "qq-progress-bar-container-selector",
+ progressBar: "qq-progress-bar-selector",
+ totalProgressBarContainer: "qq-total-progress-bar-container-selector",
+ totalProgressBar: "qq-total-progress-bar-selector",
+ file: "qq-upload-file-selector",
+ spinner: "qq-upload-spinner-selector",
+ size: "qq-upload-size-selector",
+ cancel: "qq-upload-cancel-selector",
+ pause: "qq-upload-pause-selector",
+ continueButton: "qq-upload-continue-selector",
+ deleteButton: "qq-upload-delete-selector",
+ retry: "qq-upload-retry-selector",
+ statusText: "qq-upload-status-text-selector",
+ editFilenameInput: "qq-edit-filename-selector",
+ editNameIcon: "qq-edit-filename-icon-selector",
+ dropText: "qq-upload-drop-area-text-selector",
+ dropProcessing: "qq-drop-processing-selector",
+ dropProcessingSpinner: "qq-drop-processing-spinner-selector",
+ thumbnail: "qq-thumbnail-selector"
+ }, previewGeneration = {}, cachedThumbnailNotAvailableImg = new qq.Promise(), cachedWaitingForThumbnailImg = new qq.Promise(), log, isEditElementsExist, isRetryElementExist, templateHtml, container, fileList, showThumbnails, serverScale, cacheThumbnailPlaceholders = function() {
+ var notAvailableUrl = options.placeholders.thumbnailNotAvailable, waitingUrl = options.placeholders.waitingForThumbnail, spec = {
+ maxSize: thumbnailMaxSize,
+ scale: serverScale
+ };
+ if (showThumbnails) {
+ if (notAvailableUrl) {
+ options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(function(updatedImg) {
+ cachedThumbnailNotAvailableImg.success(updatedImg);
+ }, function() {
+ cachedThumbnailNotAvailableImg.failure();
+ log("Problem loading 'not available' placeholder image at " + notAvailableUrl, "error");
+ });
+ } else {
+ cachedThumbnailNotAvailableImg.failure();
+ }
+ if (waitingUrl) {
+ options.imageGenerator.generate(waitingUrl, new Image(), spec).then(function(updatedImg) {
+ cachedWaitingForThumbnailImg.success(updatedImg);
+ }, function() {
+ cachedWaitingForThumbnailImg.failure();
+ log("Problem loading 'waiting for thumbnail' placeholder image at " + waitingUrl, "error");
+ });
+ } else {
+ cachedWaitingForThumbnailImg.failure();
+ }
+ }
+ }, displayWaitingImg = function(thumbnail) {
+ var waitingImgPlacement = new qq.Promise();
+ cachedWaitingForThumbnailImg.then(function(img) {
+ maybeScalePlaceholderViaCss(img, thumbnail);
+ if (!thumbnail.src) {
+ thumbnail.src = img.src;
+ thumbnail.onload = function() {
+ thumbnail.onload = null;
+ show(thumbnail);
+ waitingImgPlacement.success();
+ };
+ } else {
+ waitingImgPlacement.success();
+ }
+ }, function() {
+ hide(thumbnail);
+ waitingImgPlacement.success();
+ });
+ return waitingImgPlacement;
+ }, generateNewPreview = function(id, blob, spec) {
+ var thumbnail = getThumbnail(id);
+ log("Generating new thumbnail for " + id);
+ blob.qqThumbnailId = id;
+ return options.imageGenerator.generate(blob, thumbnail, spec).then(function() {
+ generatedThumbnails++;
+ show(thumbnail);
+ previewGeneration[id].success();
+ }, function() {
+ previewGeneration[id].failure();
+ if (!options.placeholders.waitUntilUpdate) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ }
+ });
+ }, generateNextQueuedPreview = function() {
+ if (thumbGenerationQueue.length) {
+ thumbnailQueueMonitorRunning = true;
+ var queuedThumbRequest = thumbGenerationQueue.shift();
+ if (queuedThumbRequest.update) {
+ processUpdateQueuedPreviewRequest(queuedThumbRequest);
+ } else {
+ processNewQueuedPreviewRequest(queuedThumbRequest);
+ }
+ } else {
+ thumbnailQueueMonitorRunning = false;
+ }
+ }, getCancel = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.cancel);
+ }, getContinue = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.continueButton);
+ }, getDialog = function(type) {
+ return getTemplateEl(container, selectorClasses[type + "Dialog"]);
+ }, getDelete = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.deleteButton);
+ }, getDropProcessing = function() {
+ return getTemplateEl(container, selectorClasses.dropProcessing);
+ }, getEditIcon = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.editNameIcon);
+ }, getFile = function(id) {
+ return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);
+ }, getFilename = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.file);
+ }, getPause = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.pause);
+ }, getProgress = function(id) {
+ if (id == null) {
+ return getTemplateEl(container, selectorClasses.totalProgressBarContainer) || getTemplateEl(container, selectorClasses.totalProgressBar);
+ }
+ return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) || getTemplateEl(getFile(id), selectorClasses.progressBar);
+ }, getRetry = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.retry);
+ }, getSize = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.size);
+ }, getSpinner = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.spinner);
+ }, getTemplateEl = function(context, cssClass) {
+ return context && qq(context).getFirstByClass(cssClass);
+ }, getThumbnail = function(id) {
+ return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);
+ }, hide = function(el) {
+ el && qq(el).addClass(options.classes.hide);
+ }, maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {
+ var maxWidth = placeholder.style.maxWidth, maxHeight = placeholder.style.maxHeight;
+ if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {
+ qq(thumbnail).css({
+ maxWidth: maxWidth,
+ maxHeight: maxHeight
+ });
+ }
+ }, maybeSetDisplayNotAvailableImg = function(id, thumbnail) {
+ var previewing = previewGeneration[id] || new qq.Promise().failure(), notAvailableImgPlacement = new qq.Promise();
+ cachedThumbnailNotAvailableImg.then(function(img) {
+ previewing.then(function() {
+ notAvailableImgPlacement.success();
+ }, function() {
+ maybeScalePlaceholderViaCss(img, thumbnail);
+ thumbnail.onload = function() {
+ thumbnail.onload = null;
+ notAvailableImgPlacement.success();
+ };
+ thumbnail.src = img.src;
+ show(thumbnail);
+ });
+ });
+ return notAvailableImgPlacement;
+ }, parseAndGetTemplate = function() {
+ var scriptEl, scriptHtml, fileListNode, tempTemplateEl, fileListHtml, defaultButton, dropArea, thumbnail, dropProcessing, dropTextEl, uploaderEl;
+ log("Parsing template");
+ if (options.templateIdOrEl == null) {
+ throw new Error("You MUST specify either a template element or ID!");
+ }
+ if (qq.isString(options.templateIdOrEl)) {
+ scriptEl = document.getElementById(options.templateIdOrEl);
+ if (scriptEl === null) {
+ throw new Error(qq.format("Cannot find template script at ID '{}'!", options.templateIdOrEl));
+ }
+ scriptHtml = scriptEl.innerHTML;
+ } else {
+ if (options.templateIdOrEl.innerHTML === undefined) {
+ throw new Error("You have specified an invalid value for the template option! " + "It must be an ID or an Element.");
+ }
+ scriptHtml = options.templateIdOrEl.innerHTML;
+ }
+ scriptHtml = qq.trimStr(scriptHtml);
+ tempTemplateEl = document.createElement("div");
+ tempTemplateEl.appendChild(qq.toElement(scriptHtml));
+ uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);
+ if (options.button) {
+ defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);
+ if (defaultButton) {
+ qq(defaultButton).remove();
+ }
+ }
+ if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {
+ dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);
+ if (dropProcessing) {
+ qq(dropProcessing).remove();
+ }
+ }
+ dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);
+ if (dropArea && !qq.DragAndDrop) {
+ log("DnD module unavailable.", "info");
+ qq(dropArea).remove();
+ }
+ if (!qq.supportedFeatures.fileDrop) {
+ uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);
+ if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {
+ qq(dropArea).css({
+ display: "none"
+ });
+ }
+ } else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {
+ dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);
+ dropTextEl && qq(dropTextEl).remove();
+ }
+ thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);
+ if (!showThumbnails) {
+ thumbnail && qq(thumbnail).remove();
+ } else if (thumbnail) {
+ thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));
+ thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;
+ serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);
+ }
+ showThumbnails = showThumbnails && thumbnail;
+ isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;
+ isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;
+ fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);
+ if (fileListNode == null) {
+ throw new Error("Could not find the file list container in the template!");
+ }
+ fileListHtml = fileListNode.innerHTML;
+ fileListNode.innerHTML = "";
+ if (tempTemplateEl.getElementsByTagName("DIALOG").length) {
+ document.createElement("dialog");
+ }
+ log("Template parsing complete");
+ return {
+ template: qq.trimStr(tempTemplateEl.innerHTML),
+ fileTemplate: qq.trimStr(fileListHtml)
+ };
+ }, prependFile = function(el, index, fileList) {
+ var parentEl = fileList, beforeEl = parentEl.firstChild;
+ if (index > 0) {
+ beforeEl = qq(parentEl).children()[index].nextSibling;
+ }
+ parentEl.insertBefore(el, beforeEl);
+ }, processNewQueuedPreviewRequest = function(queuedThumbRequest) {
+ var id = queuedThumbRequest.id, optFileOrBlob = queuedThumbRequest.optFileOrBlob, relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId, thumbnail = getThumbnail(id), spec = {
+ customResizeFunction: queuedThumbRequest.customResizeFunction,
+ maxSize: thumbnailMaxSize,
+ orient: true,
+ scale: true
+ };
+ if (qq.supportedFeatures.imagePreviews) {
+ if (thumbnail) {
+ if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ } else {
+ displayWaitingImg(thumbnail).done(function() {
+ previewGeneration[id] = new qq.Promise();
+ previewGeneration[id].done(function() {
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ });
+ if (relatedThumbnailId != null) {
+ useCachedPreview(id, relatedThumbnailId);
+ } else {
+ generateNewPreview(id, optFileOrBlob, spec);
+ }
+ });
+ }
+ } else {
+ generateNextQueuedPreview();
+ }
+ } else if (thumbnail) {
+ displayWaitingImg(thumbnail);
+ generateNextQueuedPreview();
+ }
+ }, processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {
+ var id = queuedThumbRequest.id, thumbnailUrl = queuedThumbRequest.thumbnailUrl, showWaitingImg = queuedThumbRequest.showWaitingImg, thumbnail = getThumbnail(id), spec = {
+ customResizeFunction: queuedThumbRequest.customResizeFunction,
+ scale: serverScale,
+ maxSize: thumbnailMaxSize
+ };
+ if (thumbnail) {
+ if (thumbnailUrl) {
+ if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ } else {
+ if (showWaitingImg) {
+ displayWaitingImg(thumbnail);
+ }
+ return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(function() {
+ show(thumbnail);
+ generatedThumbnails++;
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ }, function() {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ });
+ }
+ } else {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ }
+ }
+ }, setProgressBarWidth = function(id, percent) {
+ var bar = getProgress(id), progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;
+ if (bar && !qq(bar).hasClass(progressBarSelector)) {
+ bar = qq(bar).getFirstByClass(progressBarSelector);
+ }
+ if (bar) {
+ qq(bar).css({
+ width: percent + "%"
+ });
+ bar.setAttribute("aria-valuenow", percent);
+ }
+ }, show = function(el) {
+ el && qq(el).removeClass(options.classes.hide);
+ }, useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {
+ var targetThumbnail = getThumbnail(targetThumbnailId), cachedThumbnail = getThumbnail(cachedThumbnailId);
+ log(qq.format("ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));
+ previewGeneration[cachedThumbnailId].then(function() {
+ generatedThumbnails++;
+ previewGeneration[targetThumbnailId].success();
+ log(qq.format("Now using previously generated thumbnail created for ID {} on ID {}.", cachedThumbnailId, targetThumbnailId));
+ targetThumbnail.src = cachedThumbnail.src;
+ show(targetThumbnail);
+ }, function() {
+ previewGeneration[targetThumbnailId].failure();
+ if (!options.placeholders.waitUntilUpdate) {
+ maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);
+ }
+ });
+ };
+ qq.extend(options, spec);
+ log = options.log;
+ if (!qq.supportedFeatures.imagePreviews) {
+ options.limits.timeBetweenThumbs = 0;
+ options.limits.maxThumbs = 0;
+ }
+ container = options.containerEl;
+ showThumbnails = options.imageGenerator !== undefined;
+ templateHtml = parseAndGetTemplate();
+ cacheThumbnailPlaceholders();
+ qq.extend(this, {
+ render: function() {
+ log("Rendering template in DOM.");
+ generatedThumbnails = 0;
+ container.innerHTML = templateHtml.template;
+ hide(getDropProcessing());
+ this.hideTotalProgress();
+ fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);
+ log("Template rendering complete");
+ },
+ renderFailure: function(message) {
+ var cantRenderEl = qq.toElement(message);
+ container.innerHTML = "";
+ container.appendChild(cantRenderEl);
+ },
+ reset: function() {
+ this.render();
+ },
+ clearFiles: function() {
+ fileList.innerHTML = "";
+ },
+ disableCancel: function() {
+ isCancelDisabled = true;
+ },
+ addFile: function(id, name, prependInfo, hideForever, batch) {
+ var fileEl = qq.toElement(templateHtml.fileTemplate), fileNameEl = getTemplateEl(fileEl, selectorClasses.file), uploaderEl = getTemplateEl(container, selectorClasses.uploader), fileContainer = batch ? fileBatch.content : fileList, thumb;
+ if (batch) {
+ fileBatch.map[id] = fileEl;
+ }
+ qq(fileEl).addClass(FILE_CLASS_PREFIX + id);
+ uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);
+ if (fileNameEl) {
+ qq(fileNameEl).setText(name);
+ fileNameEl.setAttribute("title", name);
+ }
+ fileEl.setAttribute(FILE_ID_ATTR, id);
+ if (prependInfo) {
+ prependFile(fileEl, prependInfo.index, fileContainer);
+ } else {
+ fileContainer.appendChild(fileEl);
+ }
+ if (hideForever) {
+ fileEl.style.display = "none";
+ qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);
+ } else {
+ hide(getProgress(id));
+ hide(getSize(id));
+ hide(getDelete(id));
+ hide(getRetry(id));
+ hide(getPause(id));
+ hide(getContinue(id));
+ if (isCancelDisabled) {
+ this.hideCancel(id);
+ }
+ thumb = getThumbnail(id);
+ if (thumb && !thumb.src) {
+ cachedWaitingForThumbnailImg.then(function(waitingImg) {
+ thumb.src = waitingImg.src;
+ if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {
+ qq(thumb).css({
+ maxHeight: waitingImg.style.maxHeight,
+ maxWidth: waitingImg.style.maxWidth
+ });
+ }
+ show(thumb);
+ });
+ }
+ }
+ },
+ addFileToCache: function(id, name, prependInfo, hideForever) {
+ this.addFile(id, name, prependInfo, hideForever, true);
+ },
+ addCacheToDom: function() {
+ fileList.appendChild(fileBatch.content);
+ fileBatch.content = document.createDocumentFragment();
+ fileBatch.map = {};
+ },
+ removeFile: function(id) {
+ qq(getFile(id)).remove();
+ },
+ getFileId: function(el) {
+ var currentNode = el;
+ if (currentNode) {
+ while (currentNode.getAttribute(FILE_ID_ATTR) == null) {
+ currentNode = currentNode.parentNode;
+ }
+ return parseInt(currentNode.getAttribute(FILE_ID_ATTR));
+ }
+ },
+ getFileList: function() {
+ return fileList;
+ },
+ markFilenameEditable: function(id) {
+ var filename = getFilename(id);
+ filename && qq(filename).addClass(options.classes.editable);
+ },
+ updateFilename: function(id, name) {
+ var filenameEl = getFilename(id);
+ if (filenameEl) {
+ qq(filenameEl).setText(name);
+ filenameEl.setAttribute("title", name);
+ }
+ },
+ hideFilename: function(id) {
+ hide(getFilename(id));
+ },
+ showFilename: function(id) {
+ show(getFilename(id));
+ },
+ isFileName: function(el) {
+ return qq(el).hasClass(selectorClasses.file);
+ },
+ getButton: function() {
+ return options.button || getTemplateEl(container, selectorClasses.button);
+ },
+ hideDropProcessing: function() {
+ hide(getDropProcessing());
+ },
+ showDropProcessing: function() {
+ show(getDropProcessing());
+ },
+ getDropZone: function() {
+ return getTemplateEl(container, selectorClasses.drop);
+ },
+ isEditFilenamePossible: function() {
+ return isEditElementsExist;
+ },
+ hideRetry: function(id) {
+ hide(getRetry(id));
+ },
+ isRetryPossible: function() {
+ return isRetryElementExist;
+ },
+ showRetry: function(id) {
+ show(getRetry(id));
+ },
+ getFileContainer: function(id) {
+ return getFile(id);
+ },
+ showEditIcon: function(id) {
+ var icon = getEditIcon(id);
+ icon && qq(icon).addClass(options.classes.editable);
+ },
+ isHiddenForever: function(id) {
+ return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);
+ },
+ hideEditIcon: function(id) {
+ var icon = getEditIcon(id);
+ icon && qq(icon).removeClass(options.classes.editable);
+ },
+ isEditIcon: function(el) {
+ return qq(el).hasClass(selectorClasses.editNameIcon, true);
+ },
+ getEditInput: function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);
+ },
+ isEditInput: function(el) {
+ return qq(el).hasClass(selectorClasses.editFilenameInput, true);
+ },
+ updateProgress: function(id, loaded, total) {
+ var bar = getProgress(id), percent;
+ if (bar && total > 0) {
+ percent = Math.round(loaded / total * 100);
+ if (percent === 100) {
+ hide(bar);
+ } else {
+ show(bar);
+ }
+ setProgressBarWidth(id, percent);
+ }
+ },
+ updateTotalProgress: function(loaded, total) {
+ this.updateProgress(null, loaded, total);
+ },
+ hideProgress: function(id) {
+ var bar = getProgress(id);
+ bar && hide(bar);
+ },
+ hideTotalProgress: function() {
+ this.hideProgress();
+ },
+ resetProgress: function(id) {
+ setProgressBarWidth(id, 0);
+ this.hideTotalProgress(id);
+ },
+ resetTotalProgress: function() {
+ this.resetProgress();
+ },
+ showCancel: function(id) {
+ if (!isCancelDisabled) {
+ var cancel = getCancel(id);
+ cancel && qq(cancel).removeClass(options.classes.hide);
+ }
+ },
+ hideCancel: function(id) {
+ hide(getCancel(id));
+ },
+ isCancel: function(el) {
+ return qq(el).hasClass(selectorClasses.cancel, true);
+ },
+ allowPause: function(id) {
+ show(getPause(id));
+ hide(getContinue(id));
+ },
+ uploadPaused: function(id) {
+ this.setStatusText(id, options.text.paused);
+ this.allowContinueButton(id);
+ hide(getSpinner(id));
+ },
+ hidePause: function(id) {
+ hide(getPause(id));
+ },
+ isPause: function(el) {
+ return qq(el).hasClass(selectorClasses.pause, true);
+ },
+ isContinueButton: function(el) {
+ return qq(el).hasClass(selectorClasses.continueButton, true);
+ },
+ allowContinueButton: function(id) {
+ show(getContinue(id));
+ hide(getPause(id));
+ },
+ uploadContinued: function(id) {
+ this.setStatusText(id, "");
+ this.allowPause(id);
+ show(getSpinner(id));
+ },
+ showDeleteButton: function(id) {
+ show(getDelete(id));
+ },
+ hideDeleteButton: function(id) {
+ hide(getDelete(id));
+ },
+ isDeleteButton: function(el) {
+ return qq(el).hasClass(selectorClasses.deleteButton, true);
+ },
+ isRetry: function(el) {
+ return qq(el).hasClass(selectorClasses.retry, true);
+ },
+ updateSize: function(id, text) {
+ var size = getSize(id);
+ if (size) {
+ show(size);
+ qq(size).setText(text);
+ }
+ },
+ setStatusText: function(id, text) {
+ var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);
+ if (textEl) {
+ if (text == null) {
+ qq(textEl).clearText();
+ } else {
+ qq(textEl).setText(text);
+ }
+ }
+ },
+ hideSpinner: function(id) {
+ qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);
+ hide(getSpinner(id));
+ },
+ showSpinner: function(id) {
+ qq(getFile(id)).addClass(IN_PROGRESS_CLASS);
+ show(getSpinner(id));
+ },
+ generatePreview: function(id, optFileOrBlob, customResizeFunction) {
+ if (!this.isHiddenForever(id)) {
+ thumbGenerationQueue.push({
+ id: id,
+ customResizeFunction: customResizeFunction,
+ optFileOrBlob: optFileOrBlob
+ });
+ !thumbnailQueueMonitorRunning && generateNextQueuedPreview();
+ }
+ },
+ updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {
+ if (!this.isHiddenForever(id)) {
+ thumbGenerationQueue.push({
+ customResizeFunction: customResizeFunction,
+ update: true,
+ id: id,
+ thumbnailUrl: thumbnailUrl,
+ showWaitingImg: showWaitingImg
+ });
+ !thumbnailQueueMonitorRunning && generateNextQueuedPreview();
+ }
+ },
+ hasDialog: function(type) {
+ return qq.supportedFeatures.dialogElement && !!getDialog(type);
+ },
+ showDialog: function(type, message, defaultValue) {
+ var dialog = getDialog(type), messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage), inputEl = dialog.getElementsByTagName("INPUT")[0], cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton), okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton), promise = new qq.Promise(), closeHandler = function() {
+ cancelBtn.removeEventListener("click", cancelClickHandler);
+ okBtn && okBtn.removeEventListener("click", okClickHandler);
+ promise.failure();
+ }, cancelClickHandler = function() {
+ cancelBtn.removeEventListener("click", cancelClickHandler);
+ dialog.close();
+ }, okClickHandler = function() {
+ dialog.removeEventListener("close", closeHandler);
+ okBtn.removeEventListener("click", okClickHandler);
+ dialog.close();
+ promise.success(inputEl && inputEl.value);
+ };
+ dialog.addEventListener("close", closeHandler);
+ cancelBtn.addEventListener("click", cancelClickHandler);
+ okBtn && okBtn.addEventListener("click", okClickHandler);
+ if (inputEl) {
+ inputEl.value = defaultValue;
+ }
+ messageEl.textContent = message;
+ dialog.showModal();
+ return promise;
+ }
+ });
+ };
+ qq.UiEventHandler = function(s, protectedApi) {
+ "use strict";
+ var disposer = new qq.DisposeSupport(), spec = {
+ eventType: "click",
+ attachTo: null,
+ onHandled: function(target, event) {}
+ };
+ qq.extend(this, {
+ addHandler: function(element) {
+ addHandler(element);
+ },
+ dispose: function() {
+ disposer.dispose();
+ }
+ });
+ function addHandler(element) {
+ disposer.attach(element, spec.eventType, function(event) {
+ event = event || window.event;
+ var target = event.target || event.srcElement;
+ spec.onHandled(target, event);
+ });
+ }
+ qq.extend(protectedApi, {
+ getFileIdFromItem: function(item) {
+ return item.qqFileId;
+ },
+ getDisposeSupport: function() {
+ return disposer;
+ }
+ });
+ qq.extend(spec, s);
+ if (spec.attachTo) {
+ addHandler(spec.attachTo);
+ }
+ };
+ qq.FileButtonsClickHandler = function(s) {
+ "use strict";
+ var inheritedInternalApi = {}, spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ onDeleteFile: function(fileId) {},
+ onCancel: function(fileId) {},
+ onRetry: function(fileId) {},
+ onPause: function(fileId) {},
+ onContinue: function(fileId) {},
+ onGetName: function(fileId) {}
+ }, buttonHandlers = {
+ cancel: function(id) {
+ spec.onCancel(id);
+ },
+ retry: function(id) {
+ spec.onRetry(id);
+ },
+ deleteButton: function(id) {
+ spec.onDeleteFile(id);
+ },
+ pause: function(id) {
+ spec.onPause(id);
+ },
+ continueButton: function(id) {
+ spec.onContinue(id);
+ }
+ };
+ function examineEvent(target, event) {
+ qq.each(buttonHandlers, function(buttonType, handler) {
+ var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1), fileId;
+ if (spec.templating["is" + firstLetterCapButtonType](target)) {
+ fileId = spec.templating.getFileId(target);
+ qq.preventDefault(event);
+ spec.log(qq.format("Detected valid file button click event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ handler(fileId);
+ return false;
+ }
+ });
+ }
+ qq.extend(spec, s);
+ spec.eventType = "click";
+ spec.onHandled = examineEvent;
+ spec.attachTo = spec.templating.getFileList();
+ qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameClickHandler = function(s) {
+ "use strict";
+ var inheritedInternalApi = {}, spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ classes: {
+ file: "qq-upload-file",
+ editNameIcon: "qq-edit-filename-icon"
+ },
+ onGetUploadStatus: function(fileId) {},
+ onGetName: function(fileId) {}
+ };
+ qq.extend(spec, s);
+ function examineEvent(target, event) {
+ if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {
+ var fileId = spec.templating.getFileId(target), status = spec.onGetUploadStatus(fileId);
+ if (status === qq.status.SUBMITTED) {
+ spec.log(qq.format("Detected valid filename click event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ qq.preventDefault(event);
+ inheritedInternalApi.handleFilenameEdit(fileId, target, true);
+ }
+ }
+ }
+ spec.eventType = "click";
+ spec.onHandled = examineEvent;
+ qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {
+ "use strict";
+ var spec = {
+ templating: null,
+ onGetUploadStatus: function(fileId) {},
+ log: function(message, lvl) {}
+ };
+ if (!inheritedInternalApi) {
+ inheritedInternalApi = {};
+ }
+ function handleInputFocus(target, event) {
+ if (spec.templating.isEditInput(target)) {
+ var fileId = spec.templating.getFileId(target), status = spec.onGetUploadStatus(fileId);
+ if (status === qq.status.SUBMITTED) {
+ spec.log(qq.format("Detected valid filename input focus event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ inheritedInternalApi.handleFilenameEdit(fileId, target);
+ }
+ }
+ }
+ spec.eventType = "focusin";
+ spec.onHandled = handleInputFocus;
+ qq.extend(spec, s);
+ qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameInputFocusHandler = function(spec) {
+ "use strict";
+ spec.eventType = "focus";
+ spec.attachTo = null;
+ qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));
+ };
+ qq.FilenameEditHandler = function(s, inheritedInternalApi) {
+ "use strict";
+ var spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ onGetUploadStatus: function(fileId) {},
+ onGetName: function(fileId) {},
+ onSetName: function(fileId, newName) {},
+ onEditingStatusChange: function(fileId, isEditing) {}
+ };
+ function getFilenameSansExtension(fileId) {
+ var filenameSansExt = spec.onGetName(fileId), extIdx = filenameSansExt.lastIndexOf(".");
+ if (extIdx > 0) {
+ filenameSansExt = filenameSansExt.substr(0, extIdx);
+ }
+ return filenameSansExt;
+ }
+ function getOriginalExtension(fileId) {
+ var origName = spec.onGetName(fileId);
+ return qq.getExtension(origName);
+ }
+ function handleNameUpdate(newFilenameInputEl, fileId) {
+ var newName = newFilenameInputEl.value, origExtension;
+ if (newName !== undefined && qq.trimStr(newName).length > 0) {
+ origExtension = getOriginalExtension(fileId);
+ if (origExtension !== undefined) {
+ newName = newName + "." + origExtension;
+ }
+ spec.onSetName(fileId, newName);
+ }
+ spec.onEditingStatusChange(fileId, false);
+ }
+ function registerInputBlurHandler(inputEl, fileId) {
+ inheritedInternalApi.getDisposeSupport().attach(inputEl, "blur", function() {
+ handleNameUpdate(inputEl, fileId);
+ });
+ }
+ function registerInputEnterKeyHandler(inputEl, fileId) {
+ inheritedInternalApi.getDisposeSupport().attach(inputEl, "keyup", function(event) {
+ var code = event.keyCode || event.which;
+ if (code === 13) {
+ handleNameUpdate(inputEl, fileId);
+ }
+ });
+ }
+ qq.extend(spec, s);
+ spec.attachTo = spec.templating.getFileList();
+ qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));
+ qq.extend(inheritedInternalApi, {
+ handleFilenameEdit: function(id, target, focusInput) {
+ var newFilenameInputEl = spec.templating.getEditInput(id);
+ spec.onEditingStatusChange(id, true);
+ newFilenameInputEl.value = getFilenameSansExtension(id);
+ if (focusInput) {
+ newFilenameInputEl.focus();
+ }
+ registerInputBlurHandler(newFilenameInputEl, id);
+ registerInputEnterKeyHandler(newFilenameInputEl, id);
+ }
+ });
+ };
+ (function() {
+ "use strict";
+ qq.azure.FineUploader = function(o) {
+ var options = {
+ failedUploadTextDisplay: {
+ mode: "custom"
+ }
+ };
+ qq.extend(options, o, true);
+ qq.FineUploader.call(this, options, "azure");
+ };
+ qq.extend(qq.azure.FineUploader.prototype, qq.azure.FineUploaderBasic.prototype);
+ qq.extend(qq.azure.FineUploader.prototype, qq.uiPublicApi);
+ qq.extend(qq.azure.FineUploader.prototype, qq.uiPrivateApi);
+ qq.extend(qq.azure.FineUploader.prototype, {});
+ })();
+})(window);
+//# sourceMappingURL=azure.fine-uploader.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.js.map b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.js.map
new file mode 100644
index 000000000000..5a8f85a63752
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/azure/util.js","../client/js/non-traditional-common/uploader.basic.api.js","../client/js/azure/uploader.basic.js","../client/js/azure/azure.xhr.upload.handler.js","../client/js/azure/get-sas.js","../client/js/uploadsuccess.ajax.requester.js","../client/js/azure/rest/delete-blob.js","../client/js/azure/rest/put-blob.js","../client/js/azure/rest/put-block.js","../client/js/azure/rest/put-block-list.js","../client/js/dnd.js","../client/js/uploader.api.js","../client/js/uploader.js","../client/js/templating.js","../client/js/ui.handler.events.js","../client/js/ui.handler.click.filebuttons.js","../client/js/ui.handler.click.filename.js","../client/js/ui.handler.focusin.filenameinput.js","../client/js/ui.handler.focus.filenameinput.js","../client/js/ui.handler.edit.filename.js","../client/js/azure/uploader.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","intArray","mimeString","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","testSupportsFileInputElement","supported","tempInput","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","self","disposeSupport","options","acceptFiles","focusClass","folders","hoverClass","ios8BrowserCrashWorkaround","onChange","title","buttonId","createInput","BUTTON_ID_ATTR_NAME","setMultiple","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","byUuid","byStatus","byProxyGroupId","byBatchId","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","getDataByStatus","status","statusResults","statuses","index","statusEnum","statusResultIndexes","dataIndex","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","params","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","_options","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","promiseToReturn","fileOrUrl","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","callbacks","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","toUpperCase","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","accept","validation","allowedExtensions","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","namespace","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","messages","names","validationBase","extensionsForMessage","placeholderMatch","replacement","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","shouldParamsBeInQueryString","queue","requestData","acceptHeader","validMethods","contentType","mandatedParams","allowXRequestedWithAndCacheControl","successfulResponseCodes","DELETE","PATCH","POST","PUT","GET","onSend","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","dequeue","nextId","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","optXhr","payload","url","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","setRequestHeader","responseCode","prepareToSend","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","controller","chunkingPossible","concurrentChunkingPossible","preventRetryResponse","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","responseToReport","inProgressIdx","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","formHandlerInstanceId","onloadCallbacks","detachLoadEvents","postMessageCallbackTimers","isCors","corsMessageReceiver","expungeFile","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","_parseJsonResponse","onloadCallback","_detachLoadEvent","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","chunkFiles","resumeEnabled","xhrId","ajaxRequester","_getAjaxRequester","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","requester","getMandatedParams","_method","detectSubsampling","img","iw","naturalWidth","ih","naturalHeight","ctx","width","getContext","drawImage","getImageData","detectVerticalSquash","sy","ey","py","alpha","ratio","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","d","tmpCanvas","vertSquashRatio","dw","dh","dy","tmpCtx","sx","dx","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","imgWidth","imgHeight","opt","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","el","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetAnchor","targetProtocol","targetHostname","targetPort","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","rendered","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","TAG_IDS","TAG_INFO","274","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","vals","idHex","tagsToFindIdx","tagValHex","tagValLength","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","output","chr1","chr2","chr3","enc1","enc2","enc3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","detachPasteHandler","isImage","registerPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","formEl","_form2Obj","determineNewEndpoint","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","azure","util","AZURE_PARAM_PREFIX","_paramNameMatchesAzureParameter","_getPrefixedParamName","getParamsAsHeaders","headerName","parseAzureError","domParser","DOMParser","responseDoc","parseFromString","errorTag","errorDetails","codeTag","messageTag","nonTraditionalBasePublicApi","setUploadSuccessParams","_uploadSuccessParamsStore","setUploadSuccessEndpoint","_uploadSuccessEndpointStore","nonTraditionalBasePrivateApi","onCompleteArgs","successEndpoint","successCustomHeaders","uploadSuccess","successMethod","uploadSuccessParams","fileParams","onSuccessFromServer","successRequestResult","_failedSuccessRequestCallbacks","onFailureFromServer","submitSuccessRequest","successAjaxRequester","UploadSuccessAjaxRequester","_getEndpointSpecificParams","sendSuccessRequest","successRequestCallback","signature","blobProperties","minFileSize","_cannedBlobNames","getBlobName","onGetBlobName","_determineBlobName","deleteBlob","_deleteBlob","blobNameOptionValue","fileExtension","blobNameToUse","blobName","relatedToCancel","deleteBlobSasUri","blobUriStore","deleteFileEndpointStore","getSasSuccess","sasUri","getSasFailure","DeleteBlob","getSas","GetSas","restRequestVerb","minFileSizeForChunking","getBlobMetadata","putBlob","PutBlob","putBlock","PutBlock","putBlockList","PutBlockList","getSasForPutBlobOrBlock","combineChunks","getSignedUrl","mimeType","blockIdEntries","determineBlobUrl","containerUrl","getBlobNameSuccess","getBlobNameFailure","getSasId","getSasXhr","determineBlobUrlSuccess","blobUrl","determineBlobUrlFailure","azureError","blockIdEntry","chunkingData","maybePossible","requestPromises","sasResponseReceived","blobUri","requestPromise","restVerb","bloburi","pendingRequests","handleSuccessResponse","responseJson","successIndicator","failureIndicator","parsedResponse","codes","endpoints","promises","endpointHandler","Content-Type","createBlockId","partNum","digits","zeros","paddedPartNum","btoa","blockId","createRequestBody","doc","implementation","createDocument","latestEl","latestTextEl","createTextNode","XMLSerializer","serializeToString","fileMimeType","registerXhrCallback","blockIdsXml","x-ms-blob-content-type","DragAndDrop","HIDE_ZONES_EVENT_NAME","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","droppedFiles","dropZoneElements","allowMultipleItems","dropActive","uploadDroppedFiles","uploadDropZone","filesAsArray","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","parseEntryPromise","fullPath","indexOfNameInFullPath","qqPath","fileError","isDirectory","getFilesInDirectory","allEntriesRead","entriesLeft","readFailure","accumEntries","existingPromise","dirReader","createReader","readEntries","readSuccess","newEntries","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","dropError","setupDropzone","dropArea","dropZone","UploadDropZone","onEnter","stopPropagation","onLeaveNotDescendants","onDrop","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","relatedTarget","y","setupDragDrop","dropZones","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","targetEl","errorSpecifics","preventDrop","dropOutsideDisabled","dragoverShouldBeCanceled","disableDropOutside","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","isOrSetDropDisabled","isDisabled","triggerHidezonesEvent","hideZonesEvent","triggerUsingOldApi","createEvent","initEvent","CustomEvent","dispatchEvent","attachEvents","effect","elementFromPoint","clientX","clientY","uiPublicApi","_parent","_templating","addCacheToDom","clearFiles","addExtraDropzone","_dnd","removeExtraDropzone","getItemByFileId","isHiddenForever","getFileContainer","_setupDragAndDrop","_totalFilesInBatch","_filesInBatchAddedToUi","_setupClickAndEditEventHandlers","formattedFilename","updateFilename","uploadPaused","continued","uploadContinued","getId","fileContainerOrChildEl","getFileId","getDropTarget","qqDropTarget","uiPrivateApi","_removeFileItem","removeFile","_fileButtonsClickHandler","FileButtonsClickHandler","_bindFileButtonsClickEvent","_focusinEventSupported","_isEditFilenameEnabled","_filenameClickHandler","_bindFilenameClickEvent","_filenameInputFocusInHandler","_bindFilenameInputFocusInEvent","_filenameInputFocusHandler","_bindFilenameInputFocusEvent","dragAndDrop","extraDropzones","templating","defaultDropZone","getDropZone","showDropProcessing","hideDropProcessing","errorData","lvl","onDeleteFile","onRetry","onPause","onContinue","onGetName","isEditFilenamePossible","FilenameClickHandler","FilenameInputFocusHandler","_filenameEditHandler","onGetUploadStatus","onSetName","onEditingStatusChange","isEditing","qqInput","getEditInput","qqFileContainer","hideFilename","hideEditIcon","showFilename","showEditIcon","markFilenameEditable","hideRetry","setStatusText","_classes","retrying","hidePause","FilenameInputFocusInHandler","hideSpinner","resetTotalProgress","reportDirectoryPaths","qqpath","_addToList","addHandler","updateProgress","hideCancel","hideProgress","waitingForResponse","_displayFileSize","parentRetVal","completeUpload","_markFileAsSuccessful","fail","showCancel","isRetryPossible","showRetry","_controlFailureTextDisplay","newResult","showDeleteButton","_maybeUpdateThumbnail","showSpinner","allowPause","retryNumForDisplay","maxAuto","retryNote","_showCancelLink","showAutoRetryNote","autoRetryNote","resetProgress","_onSubmitDeleteSuccess","forceConfirm","_showDeleteConfirm","_sendDeleteRequest","deletingFailedText","hideDeleteButton","deletingStatusText","confirmMessage","deleteRequestArgs","showConfirm","canned","prependData","prependIndex","dontDisplay","hideScaled","prependFiles","disableCancel","_handledProxyGroup","_clearList","addFileToCache","updateThumbnail","thumbnails","generatePreview","fileSizeOnSubmit","loadedSize","sizeForDisplay","_formatProgress","uploadedSize","formatProgress","mode","responseProperty","failureReason","failedUploadTextDisplay","failUpload","enableTooltip","_showTooltip","showMessage","_setupPastePrompt","namePromptMessage","defaultVal","showPrompt","fileStatus","placeholders","waitUntilResponse","FineUploader","listElement","template","editable","tooManyFilesError","unsupportedBrowser","promptForName","maxCount","notAvailablePath","waitingPath","timeBetweenThumbs","hasDialog","showDialog","confirm","defaultValue","prompt","Templating","templateIdOrEl","containerEl","fileContainerEl","maxThumbs","waitUntilUpdate","thumbnailNotAvailable","waitingForThumbnail","renderFailure","FILE_ID_ATTR","FILE_CLASS_PREFIX","THUMBNAIL_MAX_SIZE_ATTR","THUMBNAIL_SERVER_SCALE_ATTR","HIDE_DROPZONE_ATTR","DROPZPONE_TEXT_ATTR","IN_PROGRESS_CLASS","HIDDEN_FOREVER_CLASS","fileBatch","content","createDocumentFragment","map","isCancelDisabled","generatedThumbnails","thumbnailQueueMonitorRunning","thumbGenerationQueue","thumbnailMaxSize","selectorClasses","alertDialog","dialogCancelButton","confirmDialog","dialogMessage","dialogOkButton","promptDialog","uploader","drop","list","progressBarContainer","totalProgressBarContainer","totalProgressBar","spinner","continueButton","deleteButton","statusText","editFilenameInput","editNameIcon","dropText","dropProcessing","dropProcessingSpinner","thumbnail","previewGeneration","cachedThumbnailNotAvailableImg","cachedWaitingForThumbnailImg","isEditElementsExist","isRetryElementExist","templateHtml","showThumbnails","serverScale","cacheThumbnailPlaceholders","notAvailableUrl","waitingUrl","updatedImg","displayWaitingImg","waitingImgPlacement","maybeScalePlaceholderViaCss","show","generateNewPreview","getThumbnail","qqThumbnailId","maybeSetDisplayNotAvailableImg","generateNextQueuedPreview","queuedThumbRequest","update","processUpdateQueuedPreviewRequest","processNewQueuedPreviewRequest","getCancel","getTemplateEl","getContinue","getDialog","getDelete","getDropProcessing","getEditIcon","getPause","getProgress","getRetry","getSpinner","cssClass","previewing","notAvailableImgPlacement","parseAndGetTemplate","scriptEl","scriptHtml","fileListNode","tempTemplateEl","fileListHtml","defaultButton","dropTextEl","uploaderEl","fileTemplate","prependFile","parentEl","beforeEl","optFileOrBlob","relatedThumbnailId","useCachedPreview","showWaitingImg","setProgressBarWidth","percent","bar","progressBarSelector","targetThumbnailId","cachedThumbnailId","targetThumbnail","cachedThumbnail","hideTotalProgress","cantRenderEl","prependInfo","hideForever","batch","fileEl","fileNameEl","thumb","waitingImg","currentNode","getFileList","filenameEl","isFileName","icon","isEditIcon","isEditInput","isCancel","allowContinueButton","isPause","isContinueButton","isDeleteButton","isRetry","textEl","dialog","messageEl","inputEl","cancelBtn","okBtn","closeHandler","cancelClickHandler","okClickHandler","close","showModal","UiEventHandler","s","protectedApi","eventType","attachTo","onHandled","srcElement","getFileIdFromItem","qqFileId","getDisposeSupport","inheritedInternalApi","buttonHandlers","examineEvent","buttonType","firstLetterCapButtonType","handleFilenameEdit","FilenameEditHandler","handleInputFocus","getFilenameSansExtension","filenameSansExt","getOriginalExtension","origName","handleNameUpdate","newFilenameInputEl","origExtension","registerInputBlurHandler","registerInputEnterKeyHandler","keyCode","which","focusInput","focus"],"mappings":"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","file":"azure.fine-uploader.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\"\"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n","/*globals qq, document, CustomEvent*/\nqq.DragAndDrop = function(o) {\n \"use strict\";\n\n var options,\n HIDE_ZONES_EVENT_NAME = \"qq-hidezones\",\n HIDE_BEFORE_ENTER_ATTR = \"qq-hide-dropzone\",\n uploadDropZones = [],\n droppedFiles = [],\n disposeSupport = new qq.DisposeSupport();\n\n options = {\n dropZoneElements: [],\n allowMultipleItems: true,\n classes: {\n dropActive: null\n },\n callbacks: new qq.DragAndDrop.callbacks()\n };\n\n qq.extend(options, o, true);\n\n function uploadDroppedFiles(files, uploadDropZone) {\n // We need to convert the `FileList` to an actual `Array` to avoid iteration issues\n var filesAsArray = Array.prototype.slice.call(files);\n\n options.callbacks.dropLog(\"Grabbed \" + files.length + \" dropped files.\");\n uploadDropZone.dropDisabled(false);\n options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());\n }\n\n function traverseFileTree(entry) {\n var parseEntryPromise = new qq.Promise();\n\n if (entry.isFile) {\n entry.file(function(file) {\n var name = entry.name,\n fullPath = entry.fullPath,\n indexOfNameInFullPath = fullPath.indexOf(name);\n\n // remove file name from full path string\n fullPath = fullPath.substr(0, indexOfNameInFullPath);\n\n // remove leading slash in full path string\n if (fullPath.charAt(0) === \"/\") {\n fullPath = fullPath.substr(1);\n }\n\n file.qqPath = fullPath;\n droppedFiles.push(file);\n parseEntryPromise.success();\n },\n function(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n });\n }\n else if (entry.isDirectory) {\n getFilesInDirectory(entry).then(\n function allEntriesRead(entries) {\n var entriesLeft = entries.length;\n\n qq.each(entries, function(idx, entry) {\n traverseFileTree(entry).done(function() {\n entriesLeft -= 1;\n\n if (entriesLeft === 0) {\n parseEntryPromise.success();\n }\n });\n });\n\n if (!entries.length) {\n parseEntryPromise.success();\n }\n },\n\n function readFailure(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n }\n );\n }\n\n return parseEntryPromise;\n }\n\n // Promissory. Guaranteed to read all files in the root of the passed directory.\n function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {\n var promise = existingPromise || new qq.Promise(),\n dirReader = reader || entry.createReader();\n\n dirReader.readEntries(\n function readSuccess(entries) {\n var newEntries = accumEntries ? accumEntries.concat(entries) : entries;\n\n if (entries.length) {\n setTimeout(function() { // prevent stack overflow, however unlikely\n getFilesInDirectory(entry, dirReader, newEntries, promise);\n }, 0);\n }\n else {\n promise.success(newEntries);\n }\n },\n\n promise.failure\n );\n\n return promise;\n }\n\n function handleDataTransfer(dataTransfer, uploadDropZone) {\n var pendingFolderPromises = [],\n handleDataTransferPromise = new qq.Promise();\n\n options.callbacks.processingDroppedFiles();\n uploadDropZone.dropDisabled(true);\n\n if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.firefox()) {\n return !e.relatedTarget;\n }\n\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n e.preventDefault();\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n // dt.types.contains check is for firefox\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains(\"Files\")));\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n};\n","/*globals qq */\n/**\n * Defines the public API for FineUploader mode.\n */\n(function() {\n \"use strict\";\n\n qq.uiPublicApi = {\n addInitialFiles: function(cannedFileList) {\n this._parent.prototype.addInitialFiles.apply(this, arguments);\n this._templating.addCacheToDom();\n },\n\n clearStoredFiles: function() {\n this._parent.prototype.clearStoredFiles.apply(this, arguments);\n this._templating.clearFiles();\n },\n\n addExtraDropzone: function(element) {\n this._dnd && this._dnd.setupExtraDropzone(element);\n },\n\n removeExtraDropzone: function(element) {\n if (this._dnd) {\n return this._dnd.removeDropzone(element);\n }\n },\n\n getItemByFileId: function(id) {\n if (!this._templating.isHiddenForever(id)) {\n return this._templating.getFileContainer(id);\n }\n },\n\n reset: function() {\n this._parent.prototype.reset.apply(this, arguments);\n this._templating.reset();\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n if (this._dnd) {\n this._dnd.dispose();\n this._dnd = this._setupDragAndDrop();\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n\n this._setupClickAndEditEventHandlers();\n },\n\n setName: function(id, newName) {\n var formattedFilename = this._options.formatFileName(newName);\n\n this._parent.prototype.setName.apply(this, arguments);\n this._templating.updateFilename(id, formattedFilename);\n },\n\n pauseUpload: function(id) {\n var paused = this._parent.prototype.pauseUpload.apply(this, arguments);\n\n paused && this._templating.uploadPaused(id);\n return paused;\n },\n\n continueUpload: function(id) {\n var continued = this._parent.prototype.continueUpload.apply(this, arguments);\n\n continued && this._templating.uploadContinued(id);\n return continued;\n },\n\n getId: function(fileContainerOrChildEl) {\n return this._templating.getFileId(fileContainerOrChildEl);\n },\n\n getDropTarget: function(fileId) {\n var file = this.getFile(fileId);\n\n return file.qqDropTarget;\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploader mode.\n */\n qq.uiPrivateApi = {\n _getButton: function(buttonId) {\n var button = this._parent.prototype._getButton.apply(this, arguments);\n\n if (!button) {\n if (buttonId === this._defaultButtonId) {\n button = this._templating.getButton();\n }\n }\n\n return button;\n },\n\n _removeFileItem: function(fileId) {\n this._templating.removeFile(fileId);\n },\n\n _setupClickAndEditEventHandlers: function() {\n this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();\n\n // A better approach would be to check specifically for focusin event support by querying the DOM API,\n // but the DOMFocusIn event is not exposed as a property, so we have to resort to UA string sniffing.\n this._focusinEventSupported = !qq.firefox();\n\n if (this._isEditFilenameEnabled())\n {\n this._filenameClickHandler = this._bindFilenameClickEvent();\n this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();\n this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();\n }\n },\n\n _setupDragAndDrop: function() {\n var self = this,\n dropZoneElements = this._options.dragAndDrop.extraDropzones,\n templating = this._templating,\n defaultDropZone = templating.getDropZone();\n\n defaultDropZone && dropZoneElements.push(defaultDropZone);\n\n return new qq.DragAndDrop({\n dropZoneElements: dropZoneElements,\n allowMultipleItems: this._options.multiple,\n classes: {\n dropActive: this._options.classes.dropActive\n },\n callbacks: {\n processingDroppedFiles: function() {\n templating.showDropProcessing();\n },\n processingDroppedFilesComplete: function(files, targetEl) {\n templating.hideDropProcessing();\n\n qq.each(files, function(idx, file) {\n file.qqDropTarget = targetEl;\n });\n\n if (files.length) {\n self.addFiles(files, null, null);\n }\n },\n dropError: function(code, errorData) {\n self._itemError(code, errorData);\n },\n dropLog: function(message, level) {\n self.log(message, level);\n }\n }\n });\n },\n\n _bindFileButtonsClickEvent: function() {\n var self = this;\n\n return new qq.FileButtonsClickHandler({\n templating: this._templating,\n\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n\n onDeleteFile: function(fileId) {\n self.deleteFile(fileId);\n },\n\n onCancel: function(fileId) {\n self.cancel(fileId);\n },\n\n onRetry: function(fileId) {\n self.retry(fileId);\n },\n\n onPause: function(fileId) {\n self.pauseUpload(fileId);\n },\n\n onContinue: function(fileId) {\n self.continueUpload(fileId);\n },\n\n onGetName: function(fileId) {\n return self.getName(fileId);\n }\n });\n },\n\n _isEditFilenameEnabled: function() {\n /*jshint -W014 */\n return this._templating.isEditFilenamePossible()\n && !this._options.autoUpload\n && qq.FilenameClickHandler\n && qq.FilenameInputFocusHandler\n && qq.FilenameInputFocusHandler;\n },\n\n _filenameEditHandler: function() {\n var self = this,\n templating = this._templating;\n\n return {\n templating: templating,\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n onGetUploadStatus: function(fileId) {\n return self.getUploads({id: fileId}).status;\n },\n onGetName: function(fileId) {\n return self.getName(fileId);\n },\n onSetName: function(id, newName) {\n self.setName(id, newName);\n },\n onEditingStatusChange: function(id, isEditing) {\n var qqInput = qq(templating.getEditInput(id)),\n qqFileContainer = qq(templating.getFileContainer(id));\n\n if (isEditing) {\n qqInput.addClass(\"qq-editing\");\n templating.hideFilename(id);\n templating.hideEditIcon(id);\n }\n else {\n qqInput.removeClass(\"qq-editing\");\n templating.showFilename(id);\n templating.showEditIcon(id);\n }\n\n // Force IE8 and older to repaint\n qqFileContainer.addClass(\"qq-temp\").removeClass(\"qq-temp\");\n }\n };\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n this._parent.prototype._onUploadStatusChange.apply(this, arguments);\n\n if (this._isEditFilenameEnabled()) {\n // Status for a file exists before it has been added to the DOM, so we must be careful here.\n if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {\n this._templating.markFilenameEditable(id);\n this._templating.hideEditIcon(id);\n }\n }\n\n if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {\n this._templating.hideRetry(id);\n this._templating.setStatusText(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);\n }\n else if (newStatus === qq.status.UPLOAD_FAILED) {\n this._templating.hidePause(id);\n }\n },\n\n _bindFilenameInputFocusInEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusInHandler(spec);\n },\n\n _bindFilenameInputFocusEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusHandler(spec);\n },\n\n _bindFilenameClickEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameClickHandler(spec);\n },\n\n _storeForLater: function(id) {\n this._parent.prototype._storeForLater.apply(this, arguments);\n this._templating.hideSpinner(id);\n },\n\n _onAllComplete: function(successful, failed) {\n this._parent.prototype._onAllComplete.apply(this, arguments);\n this._templating.resetTotalProgress();\n },\n\n _onSubmit: function(id, name) {\n var file = this.getFile(id);\n\n if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {\n this._paramsStore.addReadOnly(id, {\n qqpath: file.qqPath\n });\n }\n\n this._parent.prototype._onSubmit.apply(this, arguments);\n this._addToList(id, name);\n },\n\n // The file item has been added to the DOM.\n _onSubmitted: function(id) {\n // If the edit filename feature is enabled, mark the filename element as \"editable\" and the associated edit icon\n if (this._isEditFilenameEnabled()) {\n this._templating.markFilenameEditable(id);\n this._templating.showEditIcon(id);\n\n // If the focusin event is not supported, we must add a focus handler to the newly create edit filename text input\n if (!this._focusinEventSupported) {\n this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));\n }\n }\n },\n\n // Update the progress bar & percentage as the file is uploaded\n _onProgress: function(id, name, loaded, total) {\n this._parent.prototype._onProgress.apply(this, arguments);\n\n this._templating.updateProgress(id, loaded, total);\n\n if (total === 0 || Math.round(loaded / total * 100) === 100) {\n this._templating.hideCancel(id);\n this._templating.hidePause(id);\n this._templating.hideProgress(id);\n this._templating.setStatusText(id, this._options.text.waitingForResponse);\n\n // If ~last byte was sent, display total file size\n this._displayFileSize(id);\n }\n else {\n // If still uploading, display percentage - total size is actually the total request(s) size\n this._displayFileSize(id, loaded, total);\n }\n },\n\n _onTotalProgress: function(loaded, total) {\n this._parent.prototype._onTotalProgress.apply(this, arguments);\n this._templating.updateTotalProgress(loaded, total);\n },\n\n _onComplete: function(id, name, result, xhr) {\n var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments),\n templating = this._templating,\n fileContainer = templating.getFileContainer(id),\n self = this;\n\n function completeUpload(result) {\n // If this file is not represented in the templating module, perhaps it was hidden intentionally.\n // If so, don't perform any UI-related tasks related to this file.\n if (!fileContainer) {\n return;\n }\n\n templating.setStatusText(id);\n\n qq(fileContainer).removeClass(self._classes.retrying);\n templating.hideProgress(id);\n\n if (self.getUploads({id: id}).status !== qq.status.UPLOAD_FAILED) {\n templating.hideCancel(id);\n }\n templating.hideSpinner(id);\n\n if (result.success) {\n self._markFileAsSuccessful(id);\n }\n else {\n qq(fileContainer).addClass(self._classes.fail);\n templating.showCancel(id);\n\n if (templating.isRetryPossible() && !self._preventRetries[id]) {\n qq(fileContainer).addClass(self._classes.retryable);\n templating.showRetry(id);\n }\n self._controlFailureTextDisplay(id, result);\n }\n }\n\n // The parent may need to perform some async operation before we can accurately determine the status of the upload.\n if (parentRetVal instanceof qq.Promise) {\n parentRetVal.done(function(newResult) {\n completeUpload(newResult);\n });\n\n }\n else {\n completeUpload(result);\n }\n\n return parentRetVal;\n },\n\n _markFileAsSuccessful: function(id) {\n var templating = this._templating;\n\n if (this._isDeletePossible()) {\n templating.showDeleteButton(id);\n }\n\n qq(templating.getFileContainer(id)).addClass(this._classes.success);\n\n this._maybeUpdateThumbnail(id);\n },\n\n _onUploadPrep: function(id) {\n this._parent.prototype._onUploadPrep.apply(this, arguments);\n this._templating.showSpinner(id);\n },\n\n _onUpload: function(id, name) {\n var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);\n\n this._templating.showSpinner(id);\n\n return parentRetVal;\n },\n\n _onUploadChunk: function(id, chunkData) {\n this._parent.prototype._onUploadChunk.apply(this, arguments);\n\n // Only display the pause button if we have finished uploading at least one chunk\n // & this file can be resumed\n if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {\n this._templating.allowPause(id);\n }\n },\n\n _onCancel: function(id, name) {\n this._parent.prototype._onCancel.apply(this, arguments);\n this._removeFileItem(id);\n\n if (this._getNotFinished() === 0) {\n this._templating.resetTotalProgress();\n }\n },\n\n _onBeforeAutoRetry: function(id) {\n var retryNumForDisplay, maxAuto, retryNote;\n\n this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);\n\n this._showCancelLink(id);\n\n if (this._options.retry.showAutoRetryNote) {\n retryNumForDisplay = this._autoRetries[id];\n maxAuto = this._options.retry.maxAutoAttempts;\n\n retryNote = this._options.retry.autoRetryNote.replace(/\\{retryNum\\}/g, retryNumForDisplay);\n retryNote = retryNote.replace(/\\{maxAuto\\}/g, maxAuto);\n\n this._templating.setStatusText(id, retryNote);\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);\n }\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {\n this._templating.resetProgress(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);\n this._templating.setStatusText(id);\n this._templating.showSpinner(id);\n this._showCancelLink(id);\n return true;\n }\n else {\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);\n this._templating.showRetry(id);\n return false;\n }\n },\n\n _onSubmitDelete: function(id) {\n var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);\n\n this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);\n },\n\n _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {\n if (this._options.deleteFile.forceConfirm) {\n this._showDeleteConfirm.apply(this, arguments);\n }\n else {\n this._sendDeleteRequest.apply(this, arguments);\n }\n },\n\n _onDeleteComplete: function(id, xhr, isError) {\n this._parent.prototype._onDeleteComplete.apply(this, arguments);\n\n this._templating.hideSpinner(id);\n\n if (isError) {\n this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);\n this._templating.showDeleteButton(id);\n }\n else {\n this._removeFileItem(id);\n }\n },\n\n _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {\n this._templating.hideDeleteButton(id);\n this._templating.showSpinner(id);\n this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);\n this._deleteHandler.sendDelete.apply(this, arguments);\n },\n\n _showDeleteConfirm: function(id, uuid, mandatedParams) {\n /*jshint -W004 */\n var fileName = this.getName(id),\n confirmMessage = this._options.deleteFile.confirmMessage.replace(/\\{filename\\}/g, fileName),\n uuid = this.getUuid(id),\n deleteRequestArgs = arguments,\n self = this,\n retVal;\n\n retVal = this._options.showConfirm(confirmMessage);\n\n if (qq.isGenericPromise(retVal)) {\n retVal.then(function() {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n });\n }\n else if (retVal !== false) {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n }\n },\n\n _addToList: function(id, name, canned) {\n var prependData,\n prependIndex = 0,\n dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled,\n record;\n\n if (this._options.display.prependFiles) {\n if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {\n prependIndex = this._filesInBatchAddedToUi - 1;\n }\n\n prependData = {\n index: prependIndex\n };\n }\n\n if (!canned) {\n if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {\n this._templating.disableCancel();\n }\n\n // Cancel all existing (previous) files and clear the list if this file is not part of\n // a scaled file group that has already been accepted, or if this file is not part of\n // a scaled file group at all.\n if (!this._options.multiple) {\n record = this.getUploads({id: id});\n\n this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;\n\n if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {\n this._handler.cancelAll();\n this._clearList();\n this._handledProxyGroup = null;\n }\n }\n }\n\n if (canned) {\n this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);\n }\n else {\n this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);\n }\n\n this._filesInBatchAddedToUi += 1;\n\n if (canned ||\n (this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading)) {\n\n this._displayFileSize(id);\n }\n },\n\n _clearList: function() {\n this._templating.clearFiles();\n this.clearStoredFiles();\n },\n\n _displayFileSize: function(id, loadedSize, totalSize) {\n var size = this.getSize(id),\n sizeForDisplay = this._formatSize(size);\n\n if (size >= 0) {\n if (loadedSize !== undefined && totalSize !== undefined) {\n sizeForDisplay = this._formatProgress(loadedSize, totalSize);\n }\n\n this._templating.updateSize(id, sizeForDisplay);\n }\n },\n\n _formatProgress: function(uploadedSize, totalSize) {\n var message = this._options.text.formatProgress;\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n r(\"{percent}\", Math.round(uploadedSize / totalSize * 100));\n r(\"{total_size}\", this._formatSize(totalSize));\n return message;\n },\n\n _controlFailureTextDisplay: function(id, response) {\n var mode, responseProperty, failureReason;\n\n mode = this._options.failedUploadTextDisplay.mode;\n responseProperty = this._options.failedUploadTextDisplay.responseProperty;\n\n if (mode === \"custom\") {\n failureReason = response[responseProperty];\n if (!failureReason) {\n failureReason = this._options.text.failUpload;\n }\n\n this._templating.setStatusText(id, failureReason);\n\n if (this._options.failedUploadTextDisplay.enableTooltip) {\n this._showTooltip(id, failureReason);\n }\n }\n else if (mode === \"default\") {\n this._templating.setStatusText(id, this._options.text.failUpload);\n }\n else if (mode !== \"none\") {\n this.log(\"failedUploadTextDisplay.mode value of '\" + mode + \"' is not valid\", \"warn\");\n }\n },\n\n _showTooltip: function(id, text) {\n this._templating.getFileContainer(id).title = text;\n },\n\n _showCancelLink: function(id) {\n if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {\n this._templating.showCancel(id);\n }\n },\n\n _itemError: function(code, name, item) {\n var message = this._parent.prototype._itemError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _batchError: function(message) {\n this._parent.prototype._batchError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _setupPastePrompt: function() {\n var self = this;\n\n this._options.callbacks.onPasteReceived = function() {\n var message = self._options.paste.namePromptMessage,\n defaultVal = self._options.paste.defaultName;\n\n return self._options.showPrompt(message, defaultVal);\n };\n },\n\n _fileOrBlobRejected: function(id, name) {\n this._totalFilesInBatch -= 1;\n this._parent.prototype._fileOrBlobRejected.apply(this, arguments);\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n this._totalFilesInBatch = items.length;\n this._filesInBatchAddedToUi = 0;\n this._parent.prototype._prepareItemsForUpload.apply(this, arguments);\n },\n\n _maybeUpdateThumbnail: function(fileId) {\n var thumbnailUrl = this._thumbnailUrls[fileId],\n fileStatus = this.getUploads({id: fileId}).status;\n\n if (fileStatus !== qq.status.DELETED &&\n (thumbnailUrl ||\n this._options.thumbnails.placeholders.waitUntilResponse ||\n !qq.supportedFeatures.imagePreviews)) {\n\n // This will replace the \"waiting\" placeholder with a \"preview not available\" placeholder\n // if called with a null thumbnailUrl.\n this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id = this._parent.prototype._addCannedFile.apply(this, arguments);\n\n this._addToList(id, this.getName(id), true);\n this._templating.hideSpinner(id);\n this._templating.hideCancel(id);\n this._markFileAsSuccessful(id);\n\n return id;\n },\n\n _setSize: function(id, newSize) {\n this._parent.prototype._setSize.apply(this, arguments);\n\n this._templating.updateSize(id, this._formatSize(newSize));\n },\n\n _sessionRequestComplete: function() {\n this._templating.addCacheToDom();\n this._parent.prototype._sessionRequestComplete.apply(this, arguments);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploader mode, which is a default UI w/ drag & drop uploading.\n */\nqq.FineUploader = function(o, namespace) {\n \"use strict\";\n\n var self = this;\n\n // By default this should inherit instance data from FineUploaderBasic, but this can be overridden\n // if the (internal) caller defines a different parent. The parent is also used by\n // the private and public API functions that need to delegate to a parent function.\n this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;\n this._parent.apply(this, arguments);\n\n // Options provided by FineUploader mode\n qq.extend(this._options, {\n element: null,\n\n button: null,\n\n listElement: null,\n\n dragAndDrop: {\n extraDropzones: [],\n reportDirectoryPaths: false\n },\n\n text: {\n formatProgress: \"{percent}% of {total_size}\",\n failUpload: \"Upload failed\",\n waitingForResponse: \"Processing...\",\n paused: \"Paused\"\n },\n\n template: \"qq-template\",\n\n classes: {\n retrying: \"qq-upload-retrying\",\n retryable: \"qq-upload-retryable\",\n success: \"qq-upload-success\",\n fail: \"qq-upload-fail\",\n editable: \"qq-editable\",\n hide: \"qq-hide\",\n dropActive: \"qq-upload-drop-area-active\"\n },\n\n failedUploadTextDisplay: {\n mode: \"default\", //default, custom, or none\n responseProperty: \"error\",\n enableTooltip: true\n },\n\n messages: {\n tooManyFilesError: \"You may only drop one file\",\n unsupportedBrowser: \"Unrecoverable error - this browser does not permit file uploading of any kind.\"\n },\n\n retry: {\n showAutoRetryNote: true,\n autoRetryNote: \"Retrying {retryNum}/{maxAuto}...\"\n },\n\n deleteFile: {\n forceConfirm: false,\n confirmMessage: \"Are you sure you want to delete {filename}?\",\n deletingStatusText: \"Deleting...\",\n deletingFailedText: \"Delete failed\"\n\n },\n\n display: {\n fileSizeOnSubmit: false,\n prependFiles: false\n },\n\n paste: {\n promptForName: false,\n namePromptMessage: \"Please name this image\"\n },\n\n thumbnails: {\n customResizer: null,\n maxCount: 0,\n placeholders: {\n waitUntilResponse: false,\n notAvailablePath: null,\n waitingPath: null\n },\n timeBetweenThumbs: 750\n },\n\n scaling: {\n hideScaled: false\n },\n\n showMessage: function(message) {\n if (self._templating.hasDialog(\"alert\")) {\n return self._templating.showDialog(\"alert\", message);\n }\n else {\n setTimeout(function() {\n window.alert(message);\n }, 0);\n }\n },\n\n showConfirm: function(message) {\n if (self._templating.hasDialog(\"confirm\")) {\n return self._templating.showDialog(\"confirm\", message);\n }\n else {\n return window.confirm(message);\n }\n },\n\n showPrompt: function(message, defaultValue) {\n if (self._templating.hasDialog(\"prompt\")) {\n return self._templating.showDialog(\"prompt\", message, defaultValue);\n }\n else {\n return window.prompt(message, defaultValue);\n }\n }\n }, true);\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._templating = new qq.Templating({\n log: qq.bind(this.log, this),\n templateIdOrEl: this._options.template,\n containerEl: this._options.element,\n fileContainerEl: this._options.listElement,\n button: this._options.button,\n imageGenerator: this._imageGenerator,\n classes: {\n hide: this._options.classes.hide,\n editable: this._options.classes.editable\n },\n limits: {\n maxThumbs: this._options.thumbnails.maxCount,\n timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs\n },\n placeholders: {\n waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,\n thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,\n waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath\n },\n text: this._options.text\n });\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);\n }\n else if (!qq.supportedFeatures.uploading || (this._options.cors.expected && !qq.supportedFeatures.uploadCors)) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowser);\n }\n else {\n this._wrapCallbacks();\n\n this._templating.render();\n\n this._classes = this._options.classes;\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._setupClickAndEditEventHandlers();\n\n if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {\n this._dnd = this._setupDragAndDrop();\n }\n\n if (this._options.paste.targetElement && this._options.paste.promptForName) {\n if (qq.PasteSupport) {\n this._setupPastePrompt();\n }\n else {\n this.log(\"Paste support module not found.\", \"error\");\n }\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n }\n};\n\n// Inherit the base public & private API methods\nqq.extend(qq.FineUploader.prototype, qq.basePublicApi);\nqq.extend(qq.FineUploader.prototype, qq.basePrivateApi);\n\n// Add the FineUploader/default UI public & private UI methods, which may override some base methods.\nqq.extend(qq.FineUploader.prototype, qq.uiPublicApi);\nqq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);\n","/* globals qq */\n/* jshint -W065 */\n/**\n * Module responsible for rendering all Fine Uploader UI templates. This module also asserts at least\n * a limited amount of control over the template elements after they are added to the DOM.\n * Wherever possible, this module asserts total control over template elements present in the DOM.\n *\n * @param spec Specification object used to control various templating behaviors\n * @constructor\n */\nqq.Templating = function(spec) {\n \"use strict\";\n\n var FILE_ID_ATTR = \"qq-file-id\",\n FILE_CLASS_PREFIX = \"qq-file-id-\",\n THUMBNAIL_MAX_SIZE_ATTR = \"qq-max-size\",\n THUMBNAIL_SERVER_SCALE_ATTR = \"qq-server-scale\",\n // This variable is duplicated in the DnD module since it can function as a standalone as well\n HIDE_DROPZONE_ATTR = \"qq-hide-dropzone\",\n DROPZPONE_TEXT_ATTR = \"qq-drop-area-text\",\n IN_PROGRESS_CLASS = \"qq-in-progress\",\n HIDDEN_FOREVER_CLASS = \"qq-hidden-forever\",\n fileBatch = {\n content: document.createDocumentFragment(),\n map: {}\n },\n isCancelDisabled = false,\n generatedThumbnails = 0,\n thumbnailQueueMonitorRunning = false,\n thumbGenerationQueue = [],\n thumbnailMaxSize = -1,\n options = {\n log: null,\n limits: {\n maxThumbs: 0,\n timeBetweenThumbs: 750\n },\n templateIdOrEl: \"qq-template\",\n containerEl: null,\n fileContainerEl: null,\n button: null,\n imageGenerator: null,\n classes: {\n hide: \"qq-hide\",\n editable: \"qq-editable\"\n },\n placeholders: {\n waitUntilUpdate: false,\n thumbnailNotAvailable: null,\n waitingForThumbnail: null\n },\n text: {\n paused: \"Paused\"\n }\n },\n selectorClasses = {\n button: \"qq-upload-button-selector\",\n alertDialog: \"qq-alert-dialog-selector\",\n dialogCancelButton: \"qq-cancel-button-selector\",\n confirmDialog: \"qq-confirm-dialog-selector\",\n dialogMessage: \"qq-dialog-message-selector\",\n dialogOkButton: \"qq-ok-button-selector\",\n promptDialog: \"qq-prompt-dialog-selector\",\n uploader: \"qq-uploader-selector\",\n drop: \"qq-upload-drop-area-selector\",\n list: \"qq-upload-list-selector\",\n progressBarContainer: \"qq-progress-bar-container-selector\",\n progressBar: \"qq-progress-bar-selector\",\n totalProgressBarContainer: \"qq-total-progress-bar-container-selector\",\n totalProgressBar: \"qq-total-progress-bar-selector\",\n file: \"qq-upload-file-selector\",\n spinner: \"qq-upload-spinner-selector\",\n size: \"qq-upload-size-selector\",\n cancel: \"qq-upload-cancel-selector\",\n pause: \"qq-upload-pause-selector\",\n continueButton: \"qq-upload-continue-selector\",\n deleteButton: \"qq-upload-delete-selector\",\n retry: \"qq-upload-retry-selector\",\n statusText: \"qq-upload-status-text-selector\",\n editFilenameInput: \"qq-edit-filename-selector\",\n editNameIcon: \"qq-edit-filename-icon-selector\",\n dropText: \"qq-upload-drop-area-text-selector\",\n dropProcessing: \"qq-drop-processing-selector\",\n dropProcessingSpinner: \"qq-drop-processing-spinner-selector\",\n thumbnail: \"qq-thumbnail-selector\"\n },\n previewGeneration = {},\n cachedThumbnailNotAvailableImg = new qq.Promise(),\n cachedWaitingForThumbnailImg = new qq.Promise(),\n log,\n isEditElementsExist,\n isRetryElementExist,\n templateHtml,\n container,\n fileList,\n showThumbnails,\n serverScale,\n\n // During initialization of the templating module we should cache any\n // placeholder images so we can quickly swap them into the file list on demand.\n // Any placeholder images that cannot be loaded/found are simply ignored.\n cacheThumbnailPlaceholders = function() {\n var notAvailableUrl = options.placeholders.thumbnailNotAvailable,\n waitingUrl = options.placeholders.waitingForThumbnail,\n spec = {\n maxSize: thumbnailMaxSize,\n scale: serverScale\n };\n\n if (showThumbnails) {\n if (notAvailableUrl) {\n options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedThumbnailNotAvailableImg.success(updatedImg);\n },\n function() {\n cachedThumbnailNotAvailableImg.failure();\n log(\"Problem loading 'not available' placeholder image at \" + notAvailableUrl, \"error\");\n }\n );\n }\n else {\n cachedThumbnailNotAvailableImg.failure();\n }\n\n if (waitingUrl) {\n options.imageGenerator.generate(waitingUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedWaitingForThumbnailImg.success(updatedImg);\n },\n function() {\n cachedWaitingForThumbnailImg.failure();\n log(\"Problem loading 'waiting for thumbnail' placeholder image at \" + waitingUrl, \"error\");\n }\n );\n }\n else {\n cachedWaitingForThumbnailImg.failure();\n }\n }\n },\n\n // Displays a \"waiting for thumbnail\" type placeholder image\n // iff we were able to load it during initialization of the templating module.\n displayWaitingImg = function(thumbnail) {\n var waitingImgPlacement = new qq.Promise();\n\n cachedWaitingForThumbnailImg.then(function(img) {\n maybeScalePlaceholderViaCss(img, thumbnail);\n /* jshint eqnull:true */\n if (!thumbnail.src) {\n thumbnail.src = img.src;\n thumbnail.onload = function() {\n thumbnail.onload = null;\n show(thumbnail);\n waitingImgPlacement.success();\n };\n }\n else {\n waitingImgPlacement.success();\n }\n }, function() {\n // In some browsers (such as IE9 and older) an img w/out a src attribute\n // are displayed as \"broken\" images, so we should just hide the img tag\n // if we aren't going to display the \"waiting\" placeholder.\n hide(thumbnail);\n waitingImgPlacement.success();\n });\n\n return waitingImgPlacement;\n },\n\n generateNewPreview = function(id, blob, spec) {\n var thumbnail = getThumbnail(id);\n\n log(\"Generating new thumbnail for \" + id);\n blob.qqThumbnailId = id;\n\n return options.imageGenerator.generate(blob, thumbnail, spec).then(\n function() {\n generatedThumbnails++;\n show(thumbnail);\n previewGeneration[id].success();\n },\n function() {\n previewGeneration[id].failure();\n\n // Display the \"not available\" placeholder img only if we are\n // not expecting a thumbnail at a later point, such as in a server response.\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n }\n });\n },\n\n generateNextQueuedPreview = function() {\n if (thumbGenerationQueue.length) {\n thumbnailQueueMonitorRunning = true;\n\n var queuedThumbRequest = thumbGenerationQueue.shift();\n\n if (queuedThumbRequest.update) {\n processUpdateQueuedPreviewRequest(queuedThumbRequest);\n }\n else {\n processNewQueuedPreviewRequest(queuedThumbRequest);\n }\n }\n else {\n thumbnailQueueMonitorRunning = false;\n }\n },\n\n getCancel = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.cancel);\n },\n\n getContinue = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.continueButton);\n },\n\n getDialog = function(type) {\n return getTemplateEl(container, selectorClasses[type + \"Dialog\"]);\n },\n\n getDelete = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.deleteButton);\n },\n\n getDropProcessing = function() {\n return getTemplateEl(container, selectorClasses.dropProcessing);\n },\n\n getEditIcon = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editNameIcon);\n },\n\n getFile = function(id) {\n return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);\n },\n\n getFilename = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.file);\n },\n\n getPause = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.pause);\n },\n\n getProgress = function(id) {\n /* jshint eqnull:true */\n // Total progress bar\n if (id == null) {\n return getTemplateEl(container, selectorClasses.totalProgressBarContainer) ||\n getTemplateEl(container, selectorClasses.totalProgressBar);\n }\n\n // Per-file progress bar\n return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) ||\n getTemplateEl(getFile(id), selectorClasses.progressBar);\n },\n\n getRetry = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.retry);\n },\n\n getSize = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.size);\n },\n\n getSpinner = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.spinner);\n },\n\n getTemplateEl = function(context, cssClass) {\n return context && qq(context).getFirstByClass(cssClass);\n },\n\n getThumbnail = function(id) {\n return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);\n },\n\n hide = function(el) {\n el && qq(el).addClass(options.classes.hide);\n },\n\n // Ensures a placeholder image does not exceed any max size specified\n // via `style` attribute properties iff was not used to scale\n // the placeholder AND the target doesn't already have these `style` attribute properties set.\n maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {\n var maxWidth = placeholder.style.maxWidth,\n maxHeight = placeholder.style.maxHeight;\n\n if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {\n qq(thumbnail).css({\n maxWidth: maxWidth,\n maxHeight: maxHeight\n });\n }\n },\n\n // Displays a \"thumbnail not available\" type placeholder image\n // iff we were able to load this placeholder during initialization\n // of the templating module or after preview generation has failed.\n maybeSetDisplayNotAvailableImg = function(id, thumbnail) {\n var previewing = previewGeneration[id] || new qq.Promise().failure(),\n notAvailableImgPlacement = new qq.Promise();\n\n cachedThumbnailNotAvailableImg.then(function(img) {\n previewing.then(\n function() {\n notAvailableImgPlacement.success();\n },\n function() {\n maybeScalePlaceholderViaCss(img, thumbnail);\n\n thumbnail.onload = function() {\n thumbnail.onload = null;\n notAvailableImgPlacement.success();\n };\n\n thumbnail.src = img.src;\n show(thumbnail);\n }\n );\n });\n\n return notAvailableImgPlacement;\n },\n\n /**\n * Grabs the HTML from the script tag holding the template markup. This function will also adjust\n * some internally-tracked state variables based on the contents of the template.\n * The template is filtered so that irrelevant elements (such as the drop zone if DnD is not supported)\n * are omitted from the DOM. Useful errors will be thrown if the template cannot be parsed.\n *\n * @returns {{template: *, fileTemplate: *}} HTML for the top-level file items templates\n */\n parseAndGetTemplate = function() {\n var scriptEl,\n scriptHtml,\n fileListNode,\n tempTemplateEl,\n fileListHtml,\n defaultButton,\n dropArea,\n thumbnail,\n dropProcessing,\n dropTextEl,\n uploaderEl;\n\n log(\"Parsing template\");\n\n /*jshint -W116*/\n if (options.templateIdOrEl == null) {\n throw new Error(\"You MUST specify either a template element or ID!\");\n }\n\n // Grab the contents of the script tag holding the template.\n if (qq.isString(options.templateIdOrEl)) {\n scriptEl = document.getElementById(options.templateIdOrEl);\n\n if (scriptEl === null) {\n throw new Error(qq.format(\"Cannot find template script at ID '{}'!\", options.templateIdOrEl));\n }\n\n scriptHtml = scriptEl.innerHTML;\n }\n else {\n if (options.templateIdOrEl.innerHTML === undefined) {\n throw new Error(\"You have specified an invalid value for the template option! \" +\n \"It must be an ID or an Element.\");\n }\n\n scriptHtml = options.templateIdOrEl.innerHTML;\n }\n\n scriptHtml = qq.trimStr(scriptHtml);\n tempTemplateEl = document.createElement(\"div\");\n tempTemplateEl.appendChild(qq.toElement(scriptHtml));\n uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);\n\n // Don't include the default template button in the DOM\n // if an alternate button container has been specified.\n if (options.button) {\n defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);\n if (defaultButton) {\n qq(defaultButton).remove();\n }\n }\n\n // Omit the drop processing element from the DOM if DnD is not supported by the UA,\n // or the drag and drop module is not found.\n // NOTE: We are consciously not removing the drop zone if the UA doesn't support DnD\n // to support layouts where the drop zone is also a container for visible elements,\n // such as the file list.\n if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {\n dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);\n if (dropProcessing) {\n qq(dropProcessing).remove();\n }\n }\n\n dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);\n\n // If DnD is not available then remove\n // it from the DOM as well.\n if (dropArea && !qq.DragAndDrop) {\n log(\"DnD module unavailable.\", \"info\");\n qq(dropArea).remove();\n }\n\n if (!qq.supportedFeatures.fileDrop) {\n // don't display any \"drop files to upload\" background text\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {\n // If there is a drop area defined in the template, and the current UA doesn't support DnD,\n // and the drop area is marked as \"hide before enter\", ensure it is hidden as the DnD module\n // will not do this (since we will not be loading the DnD module)\n qq(dropArea).css({\n display: \"none\"\n });\n }\n }\n else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {\n dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);\n dropTextEl && qq(dropTextEl).remove();\n }\n\n // Ensure the `showThumbnails` flag is only set if the thumbnail element\n // is present in the template AND the current UA is capable of generating client-side previews.\n thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);\n if (!showThumbnails) {\n thumbnail && qq(thumbnail).remove();\n }\n else if (thumbnail) {\n thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));\n // Only enforce max size if the attr value is non-zero\n thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;\n\n serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);\n }\n showThumbnails = showThumbnails && thumbnail;\n\n isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;\n isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;\n\n fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);\n /*jshint -W116*/\n if (fileListNode == null) {\n throw new Error(\"Could not find the file list container in the template!\");\n }\n\n fileListHtml = fileListNode.innerHTML;\n fileListNode.innerHTML = \"\";\n\n // We must call `createElement` in IE8 in order to target and hide any via CSS\n if (tempTemplateEl.getElementsByTagName(\"DIALOG\").length) {\n document.createElement(\"dialog\");\n }\n\n log(\"Template parsing complete\");\n\n return {\n template: qq.trimStr(tempTemplateEl.innerHTML),\n fileTemplate: qq.trimStr(fileListHtml)\n };\n },\n\n prependFile = function(el, index, fileList) {\n var parentEl = fileList,\n beforeEl = parentEl.firstChild;\n\n if (index > 0) {\n beforeEl = qq(parentEl).children()[index].nextSibling;\n\n }\n\n parentEl.insertBefore(el, beforeEl);\n },\n\n processNewQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n optFileOrBlob = queuedThumbRequest.optFileOrBlob,\n relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n maxSize: thumbnailMaxSize,\n orient: true,\n scale: true\n };\n\n if (qq.supportedFeatures.imagePreviews) {\n if (thumbnail) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n displayWaitingImg(thumbnail).done(function() {\n previewGeneration[id] = new qq.Promise();\n\n previewGeneration[id].done(function() {\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n });\n\n /* jshint eqnull: true */\n // If we've already generated an for this file, use the one that exists,\n // don't waste resources generating a new one.\n if (relatedThumbnailId != null) {\n useCachedPreview(id, relatedThumbnailId);\n }\n else {\n generateNewPreview(id, optFileOrBlob, spec);\n }\n });\n }\n }\n // File element in template may have been removed, so move on to next item in queue\n else {\n generateNextQueuedPreview();\n }\n }\n else if (thumbnail) {\n displayWaitingImg(thumbnail);\n generateNextQueuedPreview();\n }\n },\n\n processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n thumbnailUrl = queuedThumbRequest.thumbnailUrl,\n showWaitingImg = queuedThumbRequest.showWaitingImg,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n scale: serverScale,\n maxSize: thumbnailMaxSize\n };\n\n if (thumbnail) {\n if (thumbnailUrl) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n if (showWaitingImg) {\n displayWaitingImg(thumbnail);\n }\n\n return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(\n function() {\n show(thumbnail);\n generatedThumbnails++;\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n },\n\n function() {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n }\n );\n }\n }\n else {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n }\n },\n\n setProgressBarWidth = function(id, percent) {\n var bar = getProgress(id),\n /* jshint eqnull:true */\n progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;\n\n if (bar && !qq(bar).hasClass(progressBarSelector)) {\n bar = qq(bar).getFirstByClass(progressBarSelector);\n }\n\n if (bar) {\n qq(bar).css({width: percent + \"%\"});\n bar.setAttribute(\"aria-valuenow\", percent);\n }\n },\n\n show = function(el) {\n el && qq(el).removeClass(options.classes.hide);\n },\n\n useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {\n var targetThumbnail = getThumbnail(targetThumbnailId),\n cachedThumbnail = getThumbnail(cachedThumbnailId);\n\n log(qq.format(\"ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.\", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));\n\n // Generation of the related thumbnail may still be in progress, so, wait until it is done.\n previewGeneration[cachedThumbnailId].then(function() {\n generatedThumbnails++;\n previewGeneration[targetThumbnailId].success();\n log(qq.format(\"Now using previously generated thumbnail created for ID {} on ID {}.\", cachedThumbnailId, targetThumbnailId));\n targetThumbnail.src = cachedThumbnail.src;\n show(targetThumbnail);\n },\n function() {\n previewGeneration[targetThumbnailId].failure();\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);\n }\n });\n };\n\n qq.extend(options, spec);\n log = options.log;\n\n // No need to worry about conserving CPU or memory on older browsers,\n // since there is no ability to preview, and thumbnail display is primitive and quick.\n if (!qq.supportedFeatures.imagePreviews) {\n options.limits.timeBetweenThumbs = 0;\n options.limits.maxThumbs = 0;\n }\n\n container = options.containerEl;\n showThumbnails = options.imageGenerator !== undefined;\n templateHtml = parseAndGetTemplate();\n\n cacheThumbnailPlaceholders();\n\n qq.extend(this, {\n render: function() {\n log(\"Rendering template in DOM.\");\n\n generatedThumbnails = 0;\n\n container.innerHTML = templateHtml.template;\n hide(getDropProcessing());\n this.hideTotalProgress();\n fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);\n\n log(\"Template rendering complete\");\n },\n\n renderFailure: function(message) {\n var cantRenderEl = qq.toElement(message);\n container.innerHTML = \"\";\n container.appendChild(cantRenderEl);\n },\n\n reset: function() {\n this.render();\n },\n\n clearFiles: function() {\n fileList.innerHTML = \"\";\n },\n\n disableCancel: function() {\n isCancelDisabled = true;\n },\n\n addFile: function(id, name, prependInfo, hideForever, batch) {\n var fileEl = qq.toElement(templateHtml.fileTemplate),\n fileNameEl = getTemplateEl(fileEl, selectorClasses.file),\n uploaderEl = getTemplateEl(container, selectorClasses.uploader),\n fileContainer = batch ? fileBatch.content : fileList,\n thumb;\n\n if (batch) {\n fileBatch.map[id] = fileEl;\n }\n\n qq(fileEl).addClass(FILE_CLASS_PREFIX + id);\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (fileNameEl) {\n qq(fileNameEl).setText(name);\n fileNameEl.setAttribute(\"title\", name);\n }\n\n fileEl.setAttribute(FILE_ID_ATTR, id);\n\n if (prependInfo) {\n prependFile(fileEl, prependInfo.index, fileContainer);\n }\n else {\n fileContainer.appendChild(fileEl);\n }\n\n if (hideForever) {\n fileEl.style.display = \"none\";\n qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);\n }\n else {\n hide(getProgress(id));\n hide(getSize(id));\n hide(getDelete(id));\n hide(getRetry(id));\n hide(getPause(id));\n hide(getContinue(id));\n\n if (isCancelDisabled) {\n this.hideCancel(id);\n }\n\n thumb = getThumbnail(id);\n if (thumb && !thumb.src) {\n cachedWaitingForThumbnailImg.then(function(waitingImg) {\n thumb.src = waitingImg.src;\n if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {\n qq(thumb).css({\n maxHeight: waitingImg.style.maxHeight,\n maxWidth: waitingImg.style.maxWidth\n });\n }\n\n show(thumb);\n });\n }\n }\n },\n\n addFileToCache: function(id, name, prependInfo, hideForever) {\n this.addFile(id, name, prependInfo, hideForever, true);\n },\n\n addCacheToDom: function() {\n fileList.appendChild(fileBatch.content);\n fileBatch.content = document.createDocumentFragment();\n fileBatch.map = {};\n },\n\n removeFile: function(id) {\n qq(getFile(id)).remove();\n },\n\n getFileId: function(el) {\n var currentNode = el;\n\n if (currentNode) {\n /*jshint -W116*/\n while (currentNode.getAttribute(FILE_ID_ATTR) == null) {\n currentNode = currentNode.parentNode;\n }\n\n return parseInt(currentNode.getAttribute(FILE_ID_ATTR));\n }\n },\n\n getFileList: function() {\n return fileList;\n },\n\n markFilenameEditable: function(id) {\n var filename = getFilename(id);\n\n filename && qq(filename).addClass(options.classes.editable);\n },\n\n updateFilename: function(id, name) {\n var filenameEl = getFilename(id);\n\n if (filenameEl) {\n qq(filenameEl).setText(name);\n filenameEl.setAttribute(\"title\", name);\n }\n },\n\n hideFilename: function(id) {\n hide(getFilename(id));\n },\n\n showFilename: function(id) {\n show(getFilename(id));\n },\n\n isFileName: function(el) {\n return qq(el).hasClass(selectorClasses.file);\n },\n\n getButton: function() {\n return options.button || getTemplateEl(container, selectorClasses.button);\n },\n\n hideDropProcessing: function() {\n hide(getDropProcessing());\n },\n\n showDropProcessing: function() {\n show(getDropProcessing());\n },\n\n getDropZone: function() {\n return getTemplateEl(container, selectorClasses.drop);\n },\n\n isEditFilenamePossible: function() {\n return isEditElementsExist;\n },\n\n hideRetry: function(id) {\n hide(getRetry(id));\n },\n\n isRetryPossible: function() {\n return isRetryElementExist;\n },\n\n showRetry: function(id) {\n show(getRetry(id));\n },\n\n getFileContainer: function(id) {\n return getFile(id);\n },\n\n showEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).addClass(options.classes.editable);\n },\n\n isHiddenForever: function(id) {\n return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);\n },\n\n hideEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).removeClass(options.classes.editable);\n },\n\n isEditIcon: function(el) {\n return qq(el).hasClass(selectorClasses.editNameIcon, true);\n },\n\n getEditInput: function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);\n },\n\n isEditInput: function(el) {\n return qq(el).hasClass(selectorClasses.editFilenameInput, true);\n },\n\n updateProgress: function(id, loaded, total) {\n var bar = getProgress(id),\n percent;\n\n if (bar && total > 0) {\n percent = Math.round(loaded / total * 100);\n\n if (percent === 100) {\n hide(bar);\n }\n else {\n show(bar);\n }\n\n setProgressBarWidth(id, percent);\n }\n },\n\n updateTotalProgress: function(loaded, total) {\n this.updateProgress(null, loaded, total);\n },\n\n hideProgress: function(id) {\n var bar = getProgress(id);\n\n bar && hide(bar);\n },\n\n hideTotalProgress: function() {\n this.hideProgress();\n },\n\n resetProgress: function(id) {\n setProgressBarWidth(id, 0);\n this.hideTotalProgress(id);\n },\n\n resetTotalProgress: function() {\n this.resetProgress();\n },\n\n showCancel: function(id) {\n if (!isCancelDisabled) {\n var cancel = getCancel(id);\n\n cancel && qq(cancel).removeClass(options.classes.hide);\n }\n },\n\n hideCancel: function(id) {\n hide(getCancel(id));\n },\n\n isCancel: function(el) {\n return qq(el).hasClass(selectorClasses.cancel, true);\n },\n\n allowPause: function(id) {\n show(getPause(id));\n hide(getContinue(id));\n },\n\n uploadPaused: function(id) {\n this.setStatusText(id, options.text.paused);\n this.allowContinueButton(id);\n hide(getSpinner(id));\n },\n\n hidePause: function(id) {\n hide(getPause(id));\n },\n\n isPause: function(el) {\n return qq(el).hasClass(selectorClasses.pause, true);\n },\n\n isContinueButton: function(el) {\n return qq(el).hasClass(selectorClasses.continueButton, true);\n },\n\n allowContinueButton: function(id) {\n show(getContinue(id));\n hide(getPause(id));\n },\n\n uploadContinued: function(id) {\n this.setStatusText(id, \"\");\n this.allowPause(id);\n show(getSpinner(id));\n },\n\n showDeleteButton: function(id) {\n show(getDelete(id));\n },\n\n hideDeleteButton: function(id) {\n hide(getDelete(id));\n },\n\n isDeleteButton: function(el) {\n return qq(el).hasClass(selectorClasses.deleteButton, true);\n },\n\n isRetry: function(el) {\n return qq(el).hasClass(selectorClasses.retry, true);\n },\n\n updateSize: function(id, text) {\n var size = getSize(id);\n\n if (size) {\n show(size);\n qq(size).setText(text);\n }\n },\n\n setStatusText: function(id, text) {\n var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);\n\n if (textEl) {\n /*jshint -W116*/\n if (text == null) {\n qq(textEl).clearText();\n }\n else {\n qq(textEl).setText(text);\n }\n }\n },\n\n hideSpinner: function(id) {\n qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);\n hide(getSpinner(id));\n },\n\n showSpinner: function(id) {\n qq(getFile(id)).addClass(IN_PROGRESS_CLASS);\n show(getSpinner(id));\n },\n\n generatePreview: function(id, optFileOrBlob, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({id: id, customResizeFunction: customResizeFunction, optFileOrBlob: optFileOrBlob});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({customResizeFunction: customResizeFunction, update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n hasDialog: function(type) {\n return qq.supportedFeatures.dialogElement && !!getDialog(type);\n },\n\n showDialog: function(type, message, defaultValue) {\n var dialog = getDialog(type),\n messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage),\n inputEl = dialog.getElementsByTagName(\"INPUT\")[0],\n cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton),\n okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton),\n promise = new qq.Promise(),\n\n closeHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.removeEventListener(\"click\", okClickHandler);\n promise.failure();\n },\n\n cancelClickHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n dialog.close();\n },\n\n okClickHandler = function() {\n dialog.removeEventListener(\"close\", closeHandler);\n okBtn.removeEventListener(\"click\", okClickHandler);\n dialog.close();\n\n promise.success(inputEl && inputEl.value);\n };\n\n dialog.addEventListener(\"close\", closeHandler);\n cancelBtn.addEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.addEventListener(\"click\", okClickHandler);\n\n if (inputEl) {\n inputEl.value = defaultValue;\n }\n messageEl.textContent = message;\n\n dialog.showModal();\n\n return promise;\n }\n });\n};\n","/*globals qq */\n// Base handler for UI (FineUploader mode) events.\n// Some more specific handlers inherit from this one.\nqq.UiEventHandler = function(s, protectedApi) {\n \"use strict\";\n\n var disposer = new qq.DisposeSupport(),\n spec = {\n eventType: \"click\",\n attachTo: null,\n onHandled: function(target, event) {}\n };\n\n // This makes up the \"public\" API methods that will be accessible\n // to instances constructing a base or child handler\n qq.extend(this, {\n addHandler: function(element) {\n addHandler(element);\n },\n\n dispose: function() {\n disposer.dispose();\n }\n });\n\n function addHandler(element) {\n disposer.attach(element, spec.eventType, function(event) {\n // Only in IE: the `event` is a property of the `window`.\n event = event || window.event;\n\n // On older browsers, we must check the `srcElement` instead of the `target`.\n var target = event.target || event.srcElement;\n\n spec.onHandled(target, event);\n });\n }\n\n // These make up the \"protected\" API methods that children of this base handler will utilize.\n qq.extend(protectedApi, {\n getFileIdFromItem: function(item) {\n return item.qqFileId;\n },\n\n getDisposeSupport: function() {\n return disposer;\n }\n });\n\n qq.extend(spec, s);\n\n if (spec.attachTo) {\n addHandler(spec.attachTo);\n }\n};\n","/* global qq */\nqq.FileButtonsClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n onDeleteFile: function(fileId) {},\n onCancel: function(fileId) {},\n onRetry: function(fileId) {},\n onPause: function(fileId) {},\n onContinue: function(fileId) {},\n onGetName: function(fileId) {}\n },\n buttonHandlers = {\n cancel: function(id) { spec.onCancel(id); },\n retry: function(id) { spec.onRetry(id); },\n deleteButton: function(id) { spec.onDeleteFile(id); },\n pause: function(id) { spec.onPause(id); },\n continueButton: function(id) { spec.onContinue(id); }\n };\n\n function examineEvent(target, event) {\n qq.each(buttonHandlers, function(buttonType, handler) {\n var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1),\n fileId;\n\n if (spec.templating[\"is\" + firstLetterCapButtonType](target)) {\n fileId = spec.templating.getFileId(target);\n qq.preventDefault(event);\n spec.log(qq.format(\"Detected valid file button click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n handler(fileId);\n return false;\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect click events on filename display elements.\nqq.FilenameClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n classes: {\n file: \"qq-upload-file\",\n editNameIcon: \"qq-edit-filename-icon\"\n },\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {}\n };\n\n qq.extend(spec, s);\n\n // This will be called by the parent handler when a `click` event is received on the list element.\n function examineEvent(target, event) {\n if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n // We only allow users to change filenames of files that have been submitted but not yet uploaded.\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n qq.preventDefault(event);\n\n inheritedInternalApi.handleFilenameEdit(fileId, target, true);\n }\n }\n }\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect focusin events on file edit input elements.\nqq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n onGetUploadStatus: function(fileId) {},\n log: function(message, lvl) {}\n };\n\n if (!inheritedInternalApi) {\n inheritedInternalApi = {};\n }\n\n // This will be called by the parent handler when a `focusin` event is received on the list element.\n function handleInputFocus(target, event) {\n if (spec.templating.isEditInput(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename input focus event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n inheritedInternalApi.handleFilenameEdit(fileId, target);\n }\n }\n }\n\n spec.eventType = \"focusin\";\n spec.onHandled = handleInputFocus;\n\n qq.extend(spec, s);\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n/**\n * Child of FilenameInputFocusInHandler. Used to detect focus events on file edit input elements. This child module is only\n * needed for UAs that do not support the focusin event. Currently, only Firefox lacks this event.\n *\n * @param spec Overrides for default specifications\n */\nqq.FilenameInputFocusHandler = function(spec) {\n \"use strict\";\n\n spec.eventType = \"focus\";\n spec.attachTo = null;\n\n qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));\n};\n","/*globals qq */\n// Handles edit-related events on a file item (FineUploader mode). This is meant to be a parent handler.\n// Children will delegate to this handler when specific edit-related actions are detected.\nqq.FilenameEditHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n log: function(message, lvl) {},\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {},\n onSetName: function(fileId, newName) {},\n onEditingStatusChange: function(fileId, isEditing) {}\n };\n\n function getFilenameSansExtension(fileId) {\n var filenameSansExt = spec.onGetName(fileId),\n extIdx = filenameSansExt.lastIndexOf(\".\");\n\n if (extIdx > 0) {\n filenameSansExt = filenameSansExt.substr(0, extIdx);\n }\n\n return filenameSansExt;\n }\n\n function getOriginalExtension(fileId) {\n var origName = spec.onGetName(fileId);\n return qq.getExtension(origName);\n }\n\n // Callback iff the name has been changed\n function handleNameUpdate(newFilenameInputEl, fileId) {\n var newName = newFilenameInputEl.value,\n origExtension;\n\n if (newName !== undefined && qq.trimStr(newName).length > 0) {\n origExtension = getOriginalExtension(fileId);\n\n if (origExtension !== undefined) {\n newName = newName + \".\" + origExtension;\n }\n\n spec.onSetName(fileId, newName);\n }\n\n spec.onEditingStatusChange(fileId, false);\n }\n\n // The name has been updated if the filename edit input loses focus.\n function registerInputBlurHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"blur\", function() {\n handleNameUpdate(inputEl, fileId);\n });\n }\n\n // The name has been updated if the user presses enter.\n function registerInputEnterKeyHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"keyup\", function(event) {\n\n var code = event.keyCode || event.which;\n\n if (code === 13) {\n handleNameUpdate(inputEl, fileId);\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n\n qq.extend(inheritedInternalApi, {\n handleFilenameEdit: function(id, target, focusInput) {\n var newFilenameInputEl = spec.templating.getEditInput(id);\n\n spec.onEditingStatusChange(id, true);\n\n newFilenameInputEl.value = getFilenameSansExtension(id);\n\n if (focusInput) {\n newFilenameInputEl.focus();\n }\n\n registerInputBlurHandler(newFilenameInputEl, id);\n registerInputEnterKeyHandler(newFilenameInputEl, id);\n }\n });\n};\n","/*globals qq */\n/**\n * This defines FineUploader mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader as well as code to handle uploads directly to Azure.\n * This module inherits all logic from UI & core mode and adds some UI-related logic\n * specific to the upload-to-Azure workflow. Some inherited options and API methods have a special meaning\n * in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploader = function(o) {\n var options = {\n failedUploadTextDisplay: {\n mode: \"custom\"\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Inherit instance data from FineUploader, which should in turn inherit from azure.FineUploaderBasic.\n qq.FineUploader.call(this, options, \"azure\");\n };\n\n // Inherit the API methods from FineUploaderBasicS3\n qq.extend(qq.azure.FineUploader.prototype, qq.azure.FineUploaderBasic.prototype);\n\n // Inherit public and private API methods related to UI\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPublicApi);\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploader.prototype, {\n });\n}());\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.min.js b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.min.js
new file mode 100644
index 000000000000..8cc5d7a2bd4b
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.min.js
@@ -0,0 +1,7 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+!function(global,global){var qq=function(e){"use strict";return{hide:function(){return e.style.display="none",this},attach:function(t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n),function(){qq(e).detach(t,n)}},detach:function(t,n){return e.removeEventListener?e.removeEventListener(t,n,!1):e.attachEvent&&e.detachEvent("on"+t,n),this},contains:function(t){return!!t&&(e===t||(e.contains?e.contains(t):!!(8&t.compareDocumentPosition(e))))},insertBefore:function(t){return t.parentNode.insertBefore(e,t),this},remove:function(){return e.parentNode.removeChild(e),this},css:function(t){if(null==e.style)throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");return null!=t.opacity&&"string"!=typeof e.style.opacity&&"undefined"!=typeof e.filters&&(t.filter="alpha(opacity="+Math.round(100*t.opacity)+")"),qq.extend(e.style,t),this},hasClass:function(t,n){var i=new RegExp("(^| )"+t+"( |$)");return i.test(e.className)||!(!n||!i.test(e.parentNode.className))},addClass:function(t){return qq(e).hasClass(t)||(e.className+=" "+t),this},removeClass:function(t){var n=new RegExp("(^| )"+t+"( |$)");return e.className=e.className.replace(n," ").replace(/^\s+|\s+$/g,""),this},getByClass:function(t,n){var i,o=[];return n&&e.querySelector?e.querySelector("."+t):e.querySelectorAll?e.querySelectorAll("."+t):(i=e.getElementsByTagName("*"),qq.each(i,function(e,n){qq(n).hasClass(t)&&o.push(n)}),n?o[0]:o)},getFirstByClass:function(t){return qq(e).getByClass(t,!0)},children:function(){for(var t=[],n=e.firstChild;n;)1===n.nodeType&&t.push(n),n=n.nextSibling;return t},setText:function(t){return e.innerText=t,e.textContent=t,this},clearText:function(){return qq(e).setText("")},hasAttribute:function(t){var n;return e.hasAttribute?!!e.hasAttribute(t)&&null==/^false$/i.exec(e.getAttribute(t)):(n=e[t],void 0!==n&&null==/^false$/i.exec(n))}}};!function(){"use strict";qq.canvasToBlob=function(e,t,n){return qq.dataUriToBlob(e.toDataURL(t,n))},qq.dataUriToBlob=function(e){var t,n,i,o,r=function(e,t){var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})};return n=e.split(",")[0].indexOf("base64")>=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),o=e.split(",")[0].split(":")[1].split(";")[0],t=new ArrayBuffer(n.length),i=new Uint8Array(t),qq.each(n,function(e,t){i[e]=t.charCodeAt(0)}),r(t,o)},qq.log=function(e,t){window.console&&(t&&"info"!==t?window.console[t]?window.console[t](e):window.console.log("<"+t+"> "+e):window.console.log(e))},qq.isObject=function(e){return e&&!e.nodeType&&"[object Object]"===Object.prototype.toString.call(e)},qq.isFunction=function(e){return"function"==typeof e},qq.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)||e&&window.ArrayBuffer&&e.buffer&&e.buffer.constructor===ArrayBuffer},qq.isItemList=function(e){return"[object DataTransferItemList]"===Object.prototype.toString.call(e)},qq.isNodeList=function(e){return"[object NodeList]"===Object.prototype.toString.call(e)||e.item&&e.namedItem},qq.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},qq.trimStr=function(e){return String.prototype.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},qq.format=function(e){var t=Array.prototype.slice.call(arguments,1),n=e,i=n.indexOf("{}");return qq.each(t,function(e,t){var o=n.substring(0,i),r=n.substring(i+2);if(n=o+t+r,i=n.indexOf("{}",i+t.length),i<0)return!1}),n},qq.isFile=function(e){return window.File&&"[object File]"===Object.prototype.toString.call(e)},qq.isFileList=function(e){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(e)},qq.isFileOrInput=function(e){return qq.isFile(e)||qq.isInput(e)},qq.isInput=function(e,t){var n=function(e){var n=e.toLowerCase();return t?"file"!==n:"file"===n};return!!(window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(e)&&e.type&&n(e.type))||!!(e.tagName&&"input"===e.tagName.toLowerCase()&&e.type&&n(e.type))},qq.isBlob=function(e){if(window.Blob&&"[object Blob]"===Object.prototype.toString.call(e))return!0},qq.isXhrUploadSupported=function(){var e=document.createElement("input");return e.type="file",void 0!==e.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&"undefined"!=typeof qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(e){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(e){return e.items&&e.items.length>0&&e.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(e,t,n){var i=e.slice||e.mozSlice||e.webkitSlice;return i.call(e,t,n)},qq.arrayBufferToHex=function(e){var t="",n=new Uint8Array(e);return qq.each(n,function(e,n){var i=n.toString(16);i.length<2&&(i="0"+i),t+=i}),t},qq.readBlobToHex=function(e,t,n){var i=qq.sliceBlob(e,t,t+n),o=new FileReader,r=new qq.Promise;return o.onload=function(){r.success(qq.arrayBufferToHex(o.result))},o.onerror=r.failure,o.readAsArrayBuffer(i),r},qq.extend=function(e,t,n){return qq.each(t,function(t,i){n&&qq.isObject(i)?(void 0===e[t]&&(e[t]={}),qq.extend(e[t],i,!0)):e[t]=i}),e},qq.override=function(e,t){var n={},i=t(n);return qq.each(i,function(t,i){void 0!==e[t]&&(n[t]=e[t]),e[t]=i}),e},qq.indexOf=function(e,t,n){if(e.indexOf)return e.indexOf(t,n);n=n||0;var i=e.length;for(n<0&&(n+=i);n=0},qq.safari=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Apple")!==-1},qq.chrome=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Google")!==-1},qq.opera=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Opera")!==-1},qq.firefox=function(){return!qq.edge()&&!qq.ie11()&&navigator.userAgent.indexOf("Mozilla")!==-1&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return navigator.userAgent.toLowerCase().indexOf("android")!==-1},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 6_")!==-1},qq.ios7=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 7_")!==-1},qq.ios8=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_")!==-1},qq.ios800=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_0 ")!==-1},qq.ios=function(){return navigator.userAgent.indexOf("iPad")!==-1||navigator.userAgent.indexOf("iPod")!==-1||navigator.userAgent.indexOf("iPhone")!==-1},qq.iosChrome=function(){return qq.ios()&&navigator.userAgent.indexOf("CriOS")!==-1},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&navigator.userAgent.indexOf("Safari")!==-1},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},qq.toElement=function(){var e=document.createElement("div");return function(t){e.innerHTML=t;var n=e.firstChild;return e.removeChild(n),n}}(),qq.each=function(e,t){var n,i;if(e)if(window.Storage&&e.constructor===window.Storage)for(n=0;n0)return e.substr(t,e.length-t)},qq.getFilename=function(e){return qq.isInput(e)?e.value.replace(/.*(\/|\\)/,""):qq.isFile(e)&&null!==e.fileName&&void 0!==e.fileName?e.fileName:e.name},qq.DisposeSupport=function(){var e=[];return{dispose:function(){var t;do t=e.shift(),t&&t();while(t)},attach:function(){var e=arguments;this.addDisposer(qq(e[0]).attach.apply(this,Array.prototype.slice.call(arguments,1)))},addDisposer:function(t){e.push(t)}}}}(),function(){"use strict";"function"==typeof define&&define.amd?define(function(){return qq}):"undefined"!=typeof module&&module.exports?module.exports=qq:global.qq=qq}(),function(){"use strict";qq.Error=function(e){this.message="[Fine Uploader "+qq.version+"] "+e},qq.Error.prototype=new Error}(),qq.version="5.13.0",qq.supportedFeatures=function(){"use strict";function e(){var e,t=!0;try{e=document.createElement("input"),e.type="file",qq(e).hide(),e.disabled&&(t=!1)}catch(e){t=!1}return t}function t(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/)}function n(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/)}function i(){if(window.XMLHttpRequest){var e=qq.createXhrInstance();return void 0!==e.withCredentials}return!1}function o(){return void 0!==window.XDomainRequest}function r(){return!!i()||o()}function a(){return void 0!==document.createElement("input").webkitdirectory}function s(){try{return!!window.localStorage&&qq.isFunction(window.localStorage.setItem)}catch(e){return!1}}function l(){var e=document.createElement("span");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&!qq.android()&&!qq.ios()}var u,c,d,p,q,h,f,m,g,_,b,v,S,y,w;return u=e(),p=u&&qq.isXhrUploadSupported(),c=p&&!qq.androidStock(),d=p&&l(),q=d&&t(),h=p&&qq.isFileChunkingSupported(),f=p&&h&&s(),m=p&&n(),g=u&&(void 0!==window.postMessage||p),b=i(),_=o(),v=r(),S=a(),y=p&&void 0!==window.FileReader,w=function(){return!!p&&(!qq.androidStock()&&!qq.iosChrome())}(),{ajaxUploading:p,blobUploading:c,canDetermineSize:p,chunking:h,deleteFileCors:v,deleteFileCorsXdr:_,deleteFileCorsXhr:b,dialogElement:!!window.HTMLDialogElement,fileDrop:d,folderDrop:q,folderSelection:S,imagePreviews:y,imageValidation:y,itemSizeValidation:p,pause:h,progressBar:w,resume:f,scaling:y&&c,tiffPreviews:qq.safari(),unlimitedScaledImageSize:!qq.ios(),uploading:u,uploadCors:g,uploadCustomHeaders:p,uploadNonMultipart:p,uploadViaPaste:m}}(),qq.isGenericPromise=function(e){"use strict";return!!(e&&e.then&&qq.isFunction(e.then))},qq.Promise=function(){"use strict";var e,t,n=[],i=[],o=[],r=0;qq.extend(this,{then:function(o,a){return 0===r?(o&&n.push(o),a&&i.push(a)):r===-1?a&&a.apply(null,t):o&&o.apply(null,e),this},done:function(n){return 0===r?o.push(n):n.apply(null,void 0===t?e:t),this},success:function(){return r=1,e=arguments,n.length&&qq.each(n,function(t,n){n.apply(null,e)}),o.length&&qq.each(o,function(t,n){n.apply(null,e)}),this},failure:function(){return r=-1,t=arguments,i.length&&qq.each(i,function(e,n){n.apply(null,t)}),o.length&&qq.each(o,function(e,n){n.apply(null,t)}),this}})},qq.BlobProxy=function(e,t){"use strict";qq.extend(this,{referenceBlob:e,create:function(){return t(e)}})},qq.UploadButton=function(e){"use strict";function t(){var e=document.createElement("input");return e.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME,i),e.setAttribute("title",a.title),o.setMultiple(a.multiple,e),a.folders&&qq.supportedFeatures.folderSelection&&e.setAttribute("webkitdirectory",""),a.acceptFiles&&e.setAttribute("accept",a.acceptFiles),e.setAttribute("type","file"),e.setAttribute("name",a.name),qq(e).css({position:"absolute",right:0,top:0,fontFamily:"Arial",fontSize:qq.ie()&&!qq.ie8()?"3500px":"118px",margin:0,padding:0,cursor:"pointer",opacity:0}),!qq.ie7()&&qq(e).css({height:"100%"}),a.element.appendChild(e),r.attach(e,"change",function(){a.onChange(e)}),r.attach(e,"mouseover",function(){qq(a.element).addClass(a.hoverClass)}),r.attach(e,"mouseout",function(){qq(a.element).removeClass(a.hoverClass)}),r.attach(e,"focus",function(){qq(a.element).addClass(a.focusClass)}),r.attach(e,"blur",function(){qq(a.element).removeClass(a.focusClass)}),e}var n,i,o=this,r=new qq.DisposeSupport,a={acceptFiles:null,element:null,focusClass:"qq-upload-button-focus",folders:!1,hoverClass:"qq-upload-button-hover",ios8BrowserCrashWorkaround:!1,multiple:!1,name:"qqfile",onChange:function(e){},title:null};qq.extend(a,e),i=qq.getUniqueId(),qq(a.element).css({position:"relative",overflow:"hidden",direction:"ltr"}),qq.extend(this,{getInput:function(){return n},getButtonId:function(){return i},setMultiple:function(e,t){var n=t||this.getInput();a.ios8BrowserCrashWorkaround&&qq.ios8()&&(qq.iosChrome()||qq.iosSafariWebView())?n.setAttribute("multiple",""):e?n.setAttribute("multiple",""):n.removeAttribute("multiple")},setAcceptFiles:function(e){e!==a.acceptFiles&&n.setAttribute("accept",e)},reset:function(){n.parentNode&&qq(n).remove(),qq(a.element).removeClass(a.focusClass),n=null,n=t()}}),n=t()},qq.UploadButton.BUTTON_ID_ATTR_NAME="qq-button-id",qq.UploadData=function(e){"use strict";function t(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[n])}),t}return o[e]}function n(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[r[n]])}),t}return o[r[e]]}function i(e){var t=[],n=[].concat(e);return qq.each(n,function(e,n){var i=a[n];void 0!==i&&qq.each(i,function(e,n){t.push(o[n])})}),t}var o=[],r={},a={},s={},l={};qq.extend(this,{addFile:function(t){var n=t.status||qq.status.SUBMITTING,i=o.push({name:t.name,originalName:t.name,uuid:t.uuid,size:null==t.size?-1:t.size,status:n})-1;return t.batchId&&(o[i].batchId=t.batchId,void 0===l[t.batchId]&&(l[t.batchId]=[]),l[t.batchId].push(i)),t.proxyGroupId&&(o[i].proxyGroupId=t.proxyGroupId,void 0===s[t.proxyGroupId]&&(s[t.proxyGroupId]=[]),s[t.proxyGroupId].push(i)),o[i].id=i,r[t.uuid]=i,void 0===a[n]&&(a[n]=[]),a[n].push(i),e.onStatusChange(i,null,n),i},retrieve:function(e){return qq.isObject(e)&&o.length?void 0!==e.id?t(e.id):void 0!==e.uuid?n(e.uuid):e.status?i(e.status):void 0:qq.extend([],o,!0)},reset:function(){o=[],r={},a={},l={}},setStatus:function(t,n){var i=o[t].status,r=qq.indexOf(a[i],t);a[i].splice(r,1),o[t].status=n,void 0===a[n]&&(a[n]=[]),a[n].push(t),e.onStatusChange(t,i,n)},uuidChanged:function(e,t){var n=o[e].uuid;o[e].uuid=t,r[t]=e,delete r[n]},updateName:function(e,t){o[e].name=t},updateSize:function(e,t){o[e].size=t},setParentId:function(e,t){o[e].parentId=t},getIdsInProxyGroup:function(e){var t=o[e].proxyGroupId;return t?s[t]:[]},getIdsInBatch:function(e){var t=o[e].batchId;return l[t]}})},qq.status={SUBMITTING:"submitting",SUBMITTED:"submitted",REJECTED:"rejected",QUEUED:"queued",CANCELED:"canceled",PAUSED:"paused",UPLOADING:"uploading",UPLOAD_RETRYING:"retrying upload",UPLOAD_SUCCESSFUL:"upload successful",UPLOAD_FAILED:"upload failed",DELETE_FAILED:"delete failed",DELETING:"deleting",DELETED:"deleted"},function(){"use strict";qq.basePublicApi={addBlobs:function(e,t,n){this.addFiles(e,t,n)},addInitialFiles:function(e){var t=this;qq.each(e,function(e,n){t._addCannedFile(n)})},addFiles:function(e,t,n){this._maybeHandleIos8SafariWorkaround();var i=0===this._storedIds.length?qq.getUniqueId():this._currentBatchId,o=qq.bind(function(e){this._handleNewFile({blob:e,name:this._options.blobs.defaultName},i,d)},this),r=qq.bind(function(e){this._handleNewFile(e,i,d)},this),a=qq.bind(function(e){var t=qq.canvasToBlob(e);this._handleNewFile({blob:t,name:this._options.blobs.defaultName+".png"},i,d)},this),s=qq.bind(function(e){var t=e.quality&&e.quality/100,n=qq.canvasToBlob(e.canvas,e.type,t);this._handleNewFile({blob:n,name:e.name},i,d)},this),l=qq.bind(function(e){if(qq.isInput(e)&&qq.supportedFeatures.ajaxUploading){var t=Array.prototype.slice.call(e.files),n=this;qq.each(t,function(e,t){n._handleNewFile(t,i,d)})}else this._handleNewFile(e,i,d)},this),u=function(){qq.isFileList(e)&&(e=Array.prototype.slice.call(e)),e=[].concat(e)},c=this,d=[];this._currentBatchId=i,e&&(u(),qq.each(e,function(e,t){qq.isFileOrInput(t)?l(t):qq.isBlob(t)?o(t):qq.isObject(t)?t.blob&&t.name?r(t):t.canvas&&t.name&&s(t):t.tagName&&"canvas"===t.tagName.toLowerCase()?a(t):c.log(t+" is not a valid file container! Ignoring!","warn")}),this.log("Received "+d.length+" files."),this._prepareItemsForUpload(d,t,n))},cancel:function(e){this._handler.cancel(e)},cancelAll:function(){var e=[],t=this;qq.extend(e,this._storedIds),qq.each(e,function(e,n){t.cancel(n)}),this._handler.cancelAll()},clearStoredFiles:function(){this._storedIds=[]},continueUpload:function(e){var t=this._uploadData.retrieve({id:e});return!(!qq.supportedFeatures.pause||!this._options.chunking.enabled)&&(t.status===qq.status.PAUSED?(this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.",e,this.getName(e))),this._uploadFile(e),!0):(this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.",e,this.getName(e)),"error"),!1))},deleteFile:function(e){return this._onSubmitDelete(e)},doesExist:function(e){return this._handler.isValid(e)},drawThumbnail:function(e,t,n,i,o){var r,a,s=new qq.Promise;return this._imageGenerator?(r=this._thumbnailUrls[e],a={customResizeFunction:o,maxSize:n>0?n:null,scale:n>0},!i&&qq.supportedFeatures.imagePreviews&&(r=this.getFile(e)),null==r?s.failure({container:t,error:"File or URL not found."}):this._imageGenerator.generate(r,t,a).then(function(e){s.success(e)},function(e,t){s.failure({container:e,error:t||"Problem generating thumbnail"})})):s.failure({container:t,error:"Missing image generator module"}),s},getButton:function(e){return this._getButton(this._buttonIdsForFileIds[e])},getEndpoint:function(e){return this._endpointStore.get(e)},getFile:function(e){return this._handler.getFile(e)||null},getInProgress:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED]}).length},getName:function(e){return this._uploadData.retrieve({id:e}).name},getParentId:function(e){var t=this.getUploads({id:e}),n=null;return t&&void 0!==t.parentId&&(n=t.parentId),n},getResumableFilesData:function(){return this._handler.getResumableFilesData()},getSize:function(e){return this._uploadData.retrieve({id:e}).size},getNetUploads:function(){return this._netUploaded},getRemainingAllowedItems:function(){var e=this._currentItemLimit;return e>0?e-this._netUploadedOrQueued:null},getUploads:function(e){return this._uploadData.retrieve(e)},getUuid:function(e){return this._uploadData.retrieve({id:e}).uuid},log:function(e,t){!this._options.debug||t&&"info"!==t?t&&"info"!==t&&qq.log("[Fine Uploader "+qq.version+"] "+e,t):qq.log("[Fine Uploader "+qq.version+"] "+e)},pauseUpload:function(e){var t=this._uploadData.retrieve({id:e});if(!qq.supportedFeatures.pause||!this._options.chunking.enabled)return!1;if(qq.indexOf([qq.status.UPLOADING,qq.status.UPLOAD_RETRYING],t.status)>=0){if(this._handler.pause(e))return this._uploadData.setStatus(e,qq.status.PAUSED),!0;this.log(qq.format("Unable to pause file ID {} ({}).",e,this.getName(e)),"error")}else this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.",e,this.getName(e)),"error");return!1},reset:function(){this.log("Resetting uploader..."),this._handler.reset(),this._storedIds=[],this._autoRetries=[],this._retryTimeouts=[],this._preventRetries=[],this._thumbnailUrls=[],qq.each(this._buttons,function(e,t){t.reset()}),this._paramsStore.reset(),this._endpointStore.reset(),this._netUploadedOrQueued=0,this._netUploaded=0,this._uploadData.reset(),this._buttonIdsForFileIds=[],this._pasteHandler&&this._pasteHandler.reset(),this._options.session.refreshOnReset&&this._refreshSessionData(),this._succeededSinceLastAllComplete=[],this._failedSinceLastAllComplete=[],this._totalProgress&&this._totalProgress.reset()},retry:function(e){return this._manualRetry(e)},scaleImage:function(e,t){var n=this;return qq.Scaler.prototype.scaleImage(e,t,{log:qq.bind(n.log,n),getFile:qq.bind(n.getFile,n),uploadData:n._uploadData})},setCustomHeaders:function(e,t){this._customHeadersStore.set(e,t)},setDeleteFileCustomHeaders:function(e,t){this._deleteFileCustomHeadersStore.set(e,t)},setDeleteFileEndpoint:function(e,t){this._deleteFileEndpointStore.set(e,t)},setDeleteFileParams:function(e,t){this._deleteFileParamsStore.set(e,t)},setEndpoint:function(e,t){this._endpointStore.set(e,t)},setForm:function(e){this._updateFormSupportAndParams(e)},setItemLimit:function(e){this._currentItemLimit=e},setName:function(e,t){this._uploadData.updateName(e,t)},setParams:function(e,t){this._paramsStore.set(e,t)},setUuid:function(e,t){return this._uploadData.uuidChanged(e,t)},uploadStoredFiles:function(){0===this._storedIds.length?this._itemError("noFilesError"):this._uploadStoredFiles()}},qq.basePrivateApi={_addCannedFile:function(e){var t=this._uploadData.addFile({uuid:e.uuid,name:e.name,size:e.size,status:qq.status.UPLOAD_SUCCESSFUL});return e.deleteFileEndpoint&&this.setDeleteFileEndpoint(e.deleteFileEndpoint,t),e.deleteFileParams&&this.setDeleteFileParams(e.deleteFileParams,t),e.thumbnailUrl&&(this._thumbnailUrls[t]=e.thumbnailUrl),this._netUploaded++,this._netUploadedOrQueued++,t},_annotateWithButtonId:function(e,t){qq.isFile(e)&&(e.qqButtonId=this._getButtonId(t))},_batchError:function(e){this._options.callbacks.onError(null,null,e,void 0)},_createDeleteHandler:function(){var e=this;return new qq.DeleteFileAjaxRequester({method:this._options.deleteFile.method.toUpperCase(),maxConnections:this._options.maxConnections,uuidParamName:this._options.request.uuidName,customHeaders:this._deleteFileCustomHeadersStore,paramsStore:this._deleteFileParamsStore,endpointStore:this._deleteFileEndpointStore,cors:this._options.cors,log:qq.bind(e.log,e),onDelete:function(t){e._onDelete(t),e._options.callbacks.onDelete(t)},onDeleteComplete:function(t,n,i){e._onDeleteComplete(t,n,i),e._options.callbacks.onDeleteComplete(t,n,i)}})},_createPasteHandler:function(){var e=this;return new qq.PasteSupport({targetElement:this._options.paste.targetElement,callbacks:{log:qq.bind(e.log,e),pasteReceived:function(t){e._handleCheckedCallback({name:"onPasteReceived",callback:qq.bind(e._options.callbacks.onPasteReceived,e,t),onSuccess:qq.bind(e._handlePasteSuccess,e,t),identifier:"pasted image"})}}})},_createStore:function(e,t){var n={},i=e,o={},r=t,a=function(e){return qq.isObject(e)?qq.extend({},e):e},s=function(){return qq.isFunction(r)?r():r},l=function(e,t){r&&qq.isObject(t)&&qq.extend(t,s()),o[e]&&qq.extend(t,o[e])};return{set:function(e,t){null==t?(n={},i=a(e)):n[t]=a(e)},get:function(e){var t;return t=null!=e&&n[e]?n[e]:a(i),l(e,t),a(t)},addReadOnly:function(e,t){qq.isObject(n)&&(null===e?qq.isFunction(t)?r=t:(r=r||{},qq.extend(r,t)):(o[e]=o[e]||{},qq.extend(o[e],t)))},remove:function(e){return delete n[e]},reset:function(){n={},o={},i=e}}},_createUploadDataTracker:function(){var e=this;return new qq.UploadData({getName:function(t){return e.getName(t)},getUuid:function(t){return e.getUuid(t)},getSize:function(t){return e.getSize(t)},onStatusChange:function(t,n,i){e._onUploadStatusChange(t,n,i),e._options.callbacks.onStatusChange(t,n,i),e._maybeAllComplete(t,i),e._totalProgress&&setTimeout(function(){e._totalProgress.onStatusChange(t,n,i)},0)}})},_createUploadButton:function(e){function t(){return!!qq.supportedFeatures.ajaxUploading&&(!(i._options.workarounds.iosEmptyVideos&&qq.ios()&&!qq.ios6()&&i._isAllowedExtension(r,".mov"))&&(void 0===e.multiple?i._options.multiple:e.multiple))}var n,i=this,o=e.accept||this._options.validation.acceptFiles,r=e.allowedExtensions||this._options.validation.allowedExtensions;return n=new qq.UploadButton({acceptFiles:o,element:e.element,focusClass:this._options.classes.buttonFocus,folders:e.folders,hoverClass:this._options.classes.buttonHover,ios8BrowserCrashWorkaround:this._options.workarounds.ios8BrowserCrash,multiple:t(),name:this._options.request.inputName,onChange:function(e){i._onInputChange(e)},title:null==e.title?this._options.text.fileInputTitle:e.title}),this._disposeSupport.addDisposer(function(){n.dispose()}),i._buttons.push(n),n},_createUploadHandler:function(e,t){var n=this,i={},o={debug:this._options.debug,maxConnections:this._options.maxConnections,cors:this._options.cors,paramsStore:this._paramsStore,endpointStore:this._endpointStore,chunking:this._options.chunking,resume:this._options.resume,blobs:this._options.blobs,log:qq.bind(n.log,n),preventRetryParam:this._options.retry.preventRetryResponseProperty,onProgress:function(e,t,o,r){o<0||r<0||(i[e]?i[e].loaded===o&&i[e].total===r||(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)):(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)),i[e]={loaded:o,total:r})},onComplete:function(e,t,o,r){delete i[e];var a,s=n.getUploads({id:e}).status;s!==qq.status.UPLOAD_SUCCESSFUL&&s!==qq.status.UPLOAD_FAILED&&(a=n._onComplete(e,t,o,r),a instanceof qq.Promise?a.done(function(){n._options.callbacks.onComplete(e,t,o,r)}):n._options.callbacks.onComplete(e,t,o,r))},onCancel:function(e,t,i){var o=new qq.Promise;return n._handleCheckedCallback({name:"onCancel",callback:qq.bind(n._options.callbacks.onCancel,n,e,t),onFailure:o.failure,onSuccess:function(){i.then(function(){n._onCancel(e,t)}),o.success()},identifier:e}),o},onUploadPrep:qq.bind(this._onUploadPrep,this),onUpload:function(e,t){n._onUpload(e,t),n._options.callbacks.onUpload(e,t)},onUploadChunk:function(e,t,i){n._onUploadChunk(e,i),n._options.callbacks.onUploadChunk(e,t,i)},onUploadChunkSuccess:function(e,t,i,o){n._options.callbacks.onUploadChunkSuccess.apply(n,arguments)},onResume:function(e,t,i){return n._options.callbacks.onResume(e,t,i)},onAutoRetry:function(e,t,i,o){return n._onAutoRetry.apply(n,arguments)},onUuidChanged:function(e,t){n.log("Server requested UUID change from '"+n.getUuid(e)+"' to '"+t+"'"),n.setUuid(e,t)},getName:qq.bind(n.getName,n),getUuid:qq.bind(n.getUuid,n),getSize:qq.bind(n.getSize,n),setSize:qq.bind(n._setSize,n),getDataByUuid:function(e){return n.getUploads({uuid:e})},isQueued:function(e){var t=n.getUploads({id:e}).status;return t===qq.status.QUEUED||t===qq.status.SUBMITTED||t===qq.status.UPLOAD_RETRYING||t===qq.status.PAUSED},getIdsInProxyGroup:n._uploadData.getIdsInProxyGroup,getIdsInBatch:n._uploadData.getIdsInBatch};return qq.each(this._options.request,function(e,t){o[e]=t}),o.customHeaders=this._customHeadersStore,e&&qq.each(e,function(e,t){o[e]=t}),new qq.UploadHandlerController(o,t)},_fileOrBlobRejected:function(e){this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.REJECTED)},_formatSize:function(e){if(0===e)return e+this._options.text.sizeSymbols[0];var t=-1;do e/=1e3,t++;while(e>999);return Math.max(e,.1).toFixed(1)+this._options.text.sizeSymbols[t]},_generateExtraButtonSpecs:function(){var e=this;this._extraButtonSpecs={},qq.each(this._options.extraButtons,function(t,n){var i=n.multiple,o=qq.extend({},e._options.validation,!0),r=qq.extend({},n);void 0===i&&(i=e._options.multiple),r.validation&&qq.extend(o,n.validation,!0),qq.extend(r,{multiple:i,validation:o},!0),e._initExtraButton(r)})},_getButton:function(e){var t=this._extraButtonSpecs[e];return t?t.element:e===this._defaultButtonId?this._options.button:void 0},_getButtonId:function(e){var t,n,i=e;if(i instanceof qq.BlobProxy&&(i=i.referenceBlob),i&&!qq.isBlob(i)){if(qq.isFile(i))return i.qqButtonId;if("input"===i.tagName.toLowerCase()&&"file"===i.type.toLowerCase())return i.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);if(t=i.getElementsByTagName("input"),qq.each(t,function(e,t){if("file"===t.getAttribute("type"))return n=t,!1}),n)return n.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME)}},_getNotFinished:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED,qq.status.SUBMITTING,qq.status.SUBMITTED,qq.status.PAUSED]}).length},_getValidationBase:function(e){var t=this._extraButtonSpecs[e];return t?t.validation:this._options.validation},_getValidationDescriptor:function(e){return e.file instanceof qq.BlobProxy?{name:qq.getFilename(e.file.referenceBlob),size:e.file.referenceBlob.size}:{name:this.getUploads({id:e.id}).name,size:this.getUploads({id:e.id}).size}},_getValidationDescriptors:function(e){var t=this,n=[];return qq.each(e,function(e,i){n.push(t._getValidationDescriptor(i))}),n},_handleCameraAccess:function(){if(this._options.camera.ios&&qq.ios()){var e="image/*;capture=camera",t=this._options.camera.button,n=t?this._getButtonId(t):this._defaultButtonId,i=this._options;n&&n!==this._defaultButtonId&&(i=this._extraButtonSpecs[n]),i.multiple=!1,null===i.validation.acceptFiles?i.validation.acceptFiles=e:i.validation.acceptFiles+=","+e,qq.each(this._buttons,function(e,t){if(t.getButtonId()===n)return t.setMultiple(i.multiple),t.setAcceptFiles(i.acceptFiles),!1})}},_handleCheckedCallback:function(e){var t=this,n=e.callback();return qq.isGenericPromise(n)?(this.log(e.name+" - waiting for "+e.name+" promise to be fulfilled for "+e.identifier),n.then(function(n){t.log(e.name+" promise success for "+e.identifier),e.onSuccess(n)},function(){e.onFailure?(t.log(e.name+" promise failure for "+e.identifier),e.onFailure()):t.log(e.name+" promise failure for "+e.identifier)})):(n!==!1?e.onSuccess(n):e.onFailure?(this.log(e.name+" - return value was 'false' for "+e.identifier+". Invoking failure callback."),e.onFailure()):this.log(e.name+" - return value was 'false' for "+e.identifier+". Will not proceed."),n)},_handleNewFile:function(e,t,n){var i=this,o=qq.getUniqueId(),r=-1,a=qq.getFilename(e),s=e.blob||e,l=this._customNewFileHandler?this._customNewFileHandler:qq.bind(i._handleNewFileGeneric,i);!qq.isInput(s)&&s.size>=0&&(r=s.size),l(s,a,o,r,n,t,this._options.request.uuidName,{uploadData:i._uploadData,paramsStore:i._paramsStore,addFileToHandler:function(e,t){i._handler.add(e,t),i._netUploadedOrQueued++,
+i._trackButton(e)}})},_handleNewFileGeneric:function(e,t,n,i,o,r){var a=this._uploadData.addFile({uuid:n,name:t,size:i,batchId:r});this._handler.add(a,e),this._trackButton(a),this._netUploadedOrQueued++,o.push({id:a,file:e})},_handlePasteSuccess:function(e,t){var n=e.type.split("/")[1],i=t;null==i&&(i=this._options.paste.defaultName),i+="."+n,this.addFiles({name:i,blob:e})},_initExtraButton:function(e){var t=this._createUploadButton({accept:e.validation.acceptFiles,allowedExtensions:e.validation.allowedExtensions,element:e.element,folders:e.folders,multiple:e.multiple,title:e.fileInputTitle});this._extraButtonSpecs[t.getButtonId()]=e},_initFormSupportAndParams:function(){this._formSupport=qq.FormSupport&&new qq.FormSupport(this._options.form,qq.bind(this.uploadStoredFiles,this),qq.bind(this.log,this)),this._formSupport&&this._formSupport.attachedToForm?(this._paramsStore=this._createStore(this._options.request.params,this._formSupport.getFormInputsAsObject),this._options.autoUpload=this._formSupport.newAutoUpload,this._formSupport.newEndpoint&&(this._options.request.endpoint=this._formSupport.newEndpoint)):this._paramsStore=this._createStore(this._options.request.params)},_isDeletePossible:function(){return!(!qq.DeleteFileAjaxRequester||!this._options.deleteFile.enabled)&&(!this._options.cors.expected||(!!qq.supportedFeatures.deleteFileCorsXhr||!(!qq.supportedFeatures.deleteFileCorsXdr||!this._options.cors.allowXdr)))},_isAllowedExtension:function(e,t){var n=!1;return!e.length||(qq.each(e,function(e,i){if(qq.isString(i)){var o=new RegExp("\\."+i+"$","i");if(null!=t.match(o))return n=!0,!1}}),n)},_itemError:function(e,t,n){function i(e,t){a=a.replace(e,t)}var o,r,a=this._options.messages[e],s=[],l=[].concat(t),u=l[0],c=this._getButtonId(n),d=this._getValidationBase(c);return qq.each(d.allowedExtensions,function(e,t){qq.isString(t)&&s.push(t)}),o=s.join(", ").toLowerCase(),i("{file}",this._options.formatFileName(u)),i("{extensions}",o),i("{sizeLimit}",this._formatSize(d.sizeLimit)),i("{minSizeLimit}",this._formatSize(d.minSizeLimit)),r=a.match(/(\{\w+\})/g),null!==r&&qq.each(r,function(e,t){i(t,l[e])}),this._options.callbacks.onError(null,u,a,void 0),a},_manualRetry:function(e,t){if(this._onBeforeManualRetry(e))return this._netUploadedOrQueued++,this._uploadData.setStatus(e,qq.status.UPLOAD_RETRYING),t?t(e):this._handler.retry(e),!0},_maybeAllComplete:function(e,t){var n=this,i=this._getNotFinished();t===qq.status.UPLOAD_SUCCESSFUL?this._succeededSinceLastAllComplete.push(e):t===qq.status.UPLOAD_FAILED&&this._failedSinceLastAllComplete.push(e),0===i&&(this._succeededSinceLastAllComplete.length||this._failedSinceLastAllComplete.length)&&setTimeout(function(){n._onAllComplete(n._succeededSinceLastAllComplete,n._failedSinceLastAllComplete)},0)},_maybeHandleIos8SafariWorkaround:function(){var e=this;if(this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari())throw setTimeout(function(){window.alert(e._options.messages.unsupportedBrowserIos8Safari)},0),new qq.Error(this._options.messages.unsupportedBrowserIos8Safari)},_maybeParseAndSendUploadError:function(e,t,n,i){if(!n.success)if(i&&200!==i.status&&!n.error)this._options.callbacks.onError(e,t,"XHR returned response code "+i.status,i);else{var o=n.error?n.error:this._options.text.defaultResponseError;this._options.callbacks.onError(e,t,o,i)}},_maybeProcessNextItemAfterOnValidateCallback:function(e,t,n,i,o){var r=this;if(t.length>n)if(e||!this._options.validation.stopOnFirstInvalidFile)setTimeout(function(){var e=r._getValidationDescriptor(t[n]),a=r._getButtonId(t[n].file),s=r._getButton(a);r._handleCheckedCallback({name:"onValidate",callback:qq.bind(r._options.callbacks.onValidate,r,e,s),onSuccess:qq.bind(r._onValidateCallbackSuccess,r,t,n,i,o),onFailure:qq.bind(r._onValidateCallbackFailure,r,t,n,i,o),identifier:"Item '"+e.name+"', size: "+e.size})},0);else if(!e)for(;n0&&this._netUploadedOrQueued+1>n?(this._itemError("retryFailTooManyItems"),!1):(this.log("Retrying upload for '"+t+"' (id: "+e+")..."),!0))):(this.log("'"+e+"' is not a valid file ID","error"),!1)},_onCancel:function(e,t){this._netUploadedOrQueued--,clearTimeout(this._retryTimeouts[e]);var n=qq.indexOf(this._storedIds,e);!this._options.autoUpload&&n>=0&&this._storedIds.splice(n,1),this._uploadData.setStatus(e,qq.status.CANCELED)},_onComplete:function(e,t,n,i){return n.success?(n.thumbnailUrl&&(this._thumbnailUrls[e]=n.thumbnailUrl),this._netUploaded++,this._uploadData.setStatus(e,qq.status.UPLOAD_SUCCESSFUL)):(this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.UPLOAD_FAILED),n[this._options.retry.preventRetryResponseProperty]===!0&&(this._preventRetries[e]=!0)),this._maybeParseAndSendUploadError(e,t,n,i),!!n.success},_onDelete:function(e){this._uploadData.setStatus(e,qq.status.DELETING)},_onDeleteComplete:function(e,t,n){var i=this.getName(e);n?(this._uploadData.setStatus(e,qq.status.DELETE_FAILED),this.log("Delete request for '"+i+"' has failed.","error"),void 0===t.withCredentials?this._options.callbacks.onError(e,i,"Delete request failed",t):this._options.callbacks.onError(e,i,"Delete request failed with response code "+t.status,t)):(this._netUploadedOrQueued--,this._netUploaded--,this._handler.expunge(e),this._uploadData.setStatus(e,qq.status.DELETED),this.log("Delete request for '"+i+"' has succeeded."))},_onInputChange:function(e){var t;if(qq.supportedFeatures.ajaxUploading){for(t=0;t0&&this.addFiles(e);qq.each(this._buttons,function(e,t){t.reset()})},_onProgress:function(e,t,n,i){this._totalProgress&&this._totalProgress.onIndividualProgress(e,n,i)},_onSubmit:function(e,t){},_onSubmitCallbackSuccess:function(e,t){this._onSubmit.apply(this,arguments),this._uploadData.setStatus(e,qq.status.SUBMITTED),this._onSubmitted.apply(this,arguments),this._options.autoUpload?(this._options.callbacks.onSubmitted.apply(this,arguments),this._uploadFile(e)):(this._storeForLater(e),this._options.callbacks.onSubmitted.apply(this,arguments))},_onSubmitDelete:function(e,t,n){var i,o=this.getUuid(e);return t&&(i=qq.bind(t,this,e,o,n)),this._isDeletePossible()?(this._handleCheckedCallback({name:"onSubmitDelete",callback:qq.bind(this._options.callbacks.onSubmitDelete,this,e),onSuccess:i||qq.bind(this._deleteHandler.sendDelete,this,e,o,n),identifier:e}),!0):(this.log("Delete request ignored for ID "+e+", delete feature is disabled or request not possible due to CORS on a user agent that does not support pre-flighting.","warn"),!1)},_onSubmitted:function(e){},_onTotalProgress:function(e,t){this._options.callbacks.onTotalProgress(e,t)},_onUploadPrep:function(e){},_onUpload:function(e,t){this._uploadData.setStatus(e,qq.status.UPLOADING)},_onUploadChunk:function(e,t){},_onUploadStatusChange:function(e,t,n){n===qq.status.PAUSED&&clearTimeout(this._retryTimeouts[e])},_onValidateBatchCallbackFailure:function(e){var t=this;qq.each(e,function(e,n){t._fileOrBlobRejected(n.id)})},_onValidateBatchCallbackSuccess:function(e,t,n,i,o){var r,a=this._currentItemLimit,s=this._netUploadedOrQueued;0===a||s<=a?t.length>0?this._handleCheckedCallback({name:"onValidate",callback:qq.bind(this._options.callbacks.onValidate,this,e[0],o),onSuccess:qq.bind(this._onValidateCallbackSuccess,this,t,0,n,i),onFailure:qq.bind(this._onValidateCallbackFailure,this,t,0,n,i),identifier:"Item '"+t[0].file.name+"', size: "+t[0].file.size}):this._itemError("noFilesError"):(this._onValidateBatchCallbackFailure(t),r=this._options.messages.tooManyItemsError.replace(/\{netItems\}/g,s).replace(/\{itemLimit\}/g,a),this._batchError(r))},_onValidateCallbackFailure:function(e,t,n,i){var o=t+1;this._fileOrBlobRejected(e[t].id,e[t].file.name),this._maybeProcessNextItemAfterOnValidateCallback(!1,e,o,n,i)},_onValidateCallbackSuccess:function(e,t,n,i){var o=this,r=t+1,a=this._getValidationDescriptor(e[t]);this._validateFileOrBlobData(e[t],a).then(function(){o._upload(e[t].id,n,i),o._maybeProcessNextItemAfterOnValidateCallback(!0,e,r,n,i)},function(){o._maybeProcessNextItemAfterOnValidateCallback(!1,e,r,n,i)})},_prepareItemsForUpload:function(e,t,n){if(0===e.length)return void this._itemError("noFilesError");var i=this._getValidationDescriptors(e),o=this._getButtonId(e[0].file),r=this._getButton(o);this._handleCheckedCallback({name:"onValidateBatch",callback:qq.bind(this._options.callbacks.onValidateBatch,this,i,r),onSuccess:qq.bind(this._onValidateBatchCallbackSuccess,this,i,e,t,n,r),onFailure:qq.bind(this._onValidateBatchCallbackFailure,this,e),identifier:"batch validation"})},_preventLeaveInProgress:function(){var e=this;this._disposeSupport.attach(window,"beforeunload",function(t){if(e.getInProgress())return t=t||window.event,t.returnValue=e._options.messages.onLeave,e._options.messages.onLeave})},_refreshSessionData:function(){var e=this,t=this._options.session;qq.Session&&null!=this._options.session.endpoint&&(this._session||(qq.extend(t,{cors:this._options.cors}),t.log=qq.bind(this.log,this),t.addFileRecord=qq.bind(this._addCannedFile,this),this._session=new qq.Session(t)),setTimeout(function(){e._session.refresh().then(function(t,n){e._sessionRequestComplete(),e._options.callbacks.onSessionRequestComplete(t,!0,n)},function(t,n){e._options.callbacks.onSessionRequestComplete(t,!1,n)})},0))},_sessionRequestComplete:function(){},_setSize:function(e,t){this._uploadData.updateSize(e,t),this._totalProgress&&this._totalProgress.onNewSize(e)},_shouldAutoRetry:function(e,t,n){var i=this._uploadData.retrieve({id:e});return!!(!this._preventRetries[e]&&this._options.retry.enableAuto&&i.status!==qq.status.PAUSED&&(void 0===this._autoRetries[e]&&(this._autoRetries[e]=0),this._autoRetries[e]0&&s.sizeLimit&&r>s.sizeLimit?(this._itemError("sizeError",o,i),l.failure()):r>0&&r=0}function n(e){var t=!1;return qq.each(t,function(e,n){if(qq.indexOf(["Accept","Accept-Language","Content-Language","Content-Type"],n)<0)return t=!0,!1}),t}function i(e){return y.cors.expected&&void 0===e.withCredentials}function o(){var e;return(window.XMLHttpRequest||window.ActiveXObject)&&(e=qq.createXhrInstance(),void 0===e.withCredentials&&(e=new XDomainRequest,e.onload=function(){},e.onerror=function(){},e.ontimeout=function(){},e.onprogress=function(){})),e}function r(e,t){var n=S[e].xhr;return n||(n=t?t:y.cors.expected?o():qq.createXhrInstance(),S[e].xhr=n),n}function a(e){var t,n=qq.indexOf(v,e),i=y.maxConnections;delete S[e],v.splice(n,1),v.length>=i&&n=0?o.send(qq.obj2url(s,"")):s&&y.contentType&&y.contentType.toLowerCase().indexOf("application/json")>=0?o.send(JSON.stringify(s)):o.send(s),o}function c(e,t,n){var i=y.endpointStore.get(e),o=S[e].addToPath;return void 0!=o&&(i+="/"+o),b&&t&&(i=qq.obj2url(t,i)),n&&(i=qq.obj2url(n,i)),i}function d(e){return function(){4===r(e).readyState&&s(e)}}function p(e){var t=y.onProgress;t&&(r(e).upload.onprogress=function(n){n.lengthComputable&&t(e,n.loaded,n.total)})}function q(e){return function(){s(e)}}function h(e){return function(){s(e,!0)}}function f(e){var o=r(e),a=y.customHeaders,s=S[e].additionalHeaders||{},l=y.method,u={};i(o)||(y.acceptHeader&&o.setRequestHeader("Accept",y.acceptHeader),y.allowXRequestedWithAndCacheControl&&(y.cors.expected&&t()&&!n(a)||(o.setRequestHeader("X-Requested-With","XMLHttpRequest"),o.setRequestHeader("Cache-Control","no-cache"))),!y.contentType||"POST"!==l&&"PUT"!==l||o.setRequestHeader("Content-Type",y.contentType),qq.extend(u,qq.isFunction(a)?a(e):a),qq.extend(u,s),qq.each(u,function(e,t){o.setRequestHeader(e,t)}))}function m(e){return qq.indexOf(y.successfulResponseCodes[y.method],e)>=0}function g(e,t,n,i,o,r,a){S[e]={addToPath:n,additionalParams:i,additionalQueryParams:o,additionalHeaders:r,payload:a};var s=v.push(e);if(s<=y.maxConnections)return u(e,t)}var _,b,v=[],S={},y={acceptHeader:null,validMethods:["PATCH","POST","PUT"],method:"POST",contentType:"application/x-www-form-urlencoded",maxConnections:3,customHeaders:{},endpointStore:{},paramsStore:{},mandatedParams:{},allowXRequestedWithAndCacheControl:!0,successfulResponseCodes:{DELETE:[200,202,204],PATCH:[200,201,202,203,204],POST:[200,201,202,203,204],PUT:[200,201,202,203,204],GET:[200]},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onSend:function(e){},onComplete:function(e,t,n){},onProgress:null};if(qq.extend(y,e),_=y.log,qq.indexOf(y.validMethods,y.method)<0)throw new Error("'"+y.method+"' is not a supported method for this type of request!");b="GET"===y.method||"DELETE"===y.method,qq.extend(this,{initTransport:function(e){var t,n,i,o,r,a;return{withPath:function(e){return t=e,this},withParams:function(e){return n=e,this},withQueryParams:function(e){return a=e,this},withHeaders:function(e){return i=e,this},withPayload:function(e){return o=e,this},withCacheBuster:function(){return r=!0,this},send:function(s){return r&&qq.indexOf(["GET","DELETE"],y.method)>=0&&(n.qqtimestamp=(new Date).getTime()),g(e,s,t,n,a,i,o)}}},canceled:function(e){a(e)}})},qq.UploadHandler=function(e){"use strict";var t=e.proxy,n={},i=t.onCancel,o=t.getName;qq.extend(this,{add:function(e,t){n[e]=t,n[e].temp={}},cancel:function(e){var t=this,r=new qq.Promise,a=i(e,o(e),r);a.then(function(){t.isValid(e)&&(n[e].canceled=!0,t.expunge(e)),r.success()})},expunge:function(e){delete n[e]},getThirdPartyFileId:function(e){return n[e].key},isValid:function(e){return void 0!==n[e]},reset:function(){n={}},_getFileState:function(e){return n[e]},_setThirdPartyFileId:function(e,t){n[e].key=t},_wasCanceled:function(e){return!!n[e].canceled}})},qq.UploadHandlerController=function(e,t){"use strict";var n,i,o,r=this,a=!1,s=!1,l={paramsStore:{},maxConnections:3,chunking:{enabled:!1,multiple:{enabled:!1}},log:function(e,t){},onProgress:function(e,t,n,i){},onComplete:function(e,t,n,i){},onCancel:function(e,t){},onUploadPrep:function(e){},onUpload:function(e,t){},onUploadChunk:function(e,t,n){},onUploadChunkSuccess:function(e,t,n,i){},onAutoRetry:function(e,t,n,i){},onResume:function(e,t,n){},onUuidChanged:function(e,t){},getName:function(e){},setSize:function(e,t){},isQueued:function(e){},getIdsInProxyGroup:function(e){},getIdsInBatch:function(e){}},u={done:function(e,t,n,i){var r=o._getChunkData(e,t);o._getFileState(e).attemptingResume=!1,delete o._getFileState(e).temp.chunkProgress[t],o._getFileState(e).loaded+=r.size,l.onUploadChunkSuccess(e,o._getChunkDataForCallback(r),n,i)},finalize:function(e){var t=l.getSize(e),n=l.getName(e);i("All chunks have been uploaded for "+e+" - finalizing...."),o.finalizeChunks(e).then(function(r,a){i("Finalize successful for "+e);var s=p.normalizeResponse(r,!0);l.onProgress(e,n,t,t),o._maybeDeletePersistedChunkData(e),p.cleanup(e,s,a)},function(t,o){var r=p.normalizeResponse(t,!1);i("Problem finalizing chunks for file ID "+e+" - "+r.error,"error"),r.reset&&u.reset(e),l.onAutoRetry(e,n,r,o)||p.cleanup(e,r,o)})},handleFailure:function(e,t,n,r){var a=l.getName(t);i("Chunked upload request failed for "+t+", chunk "+e),o.clearCachedChunk(t,e);var d,q=p.normalizeResponse(n,!1);q.reset?u.reset(t):(d=qq.indexOf(o._getFileState(t).chunking.inProgress,e),d>=0&&(o._getFileState(t).chunking.inProgress.splice(d,1),o._getFileState(t).chunking.remaining.unshift(e))),o._getFileState(t).temp.ignoreFailure||(s&&(o._getFileState(t).temp.ignoreFailure=!0,i(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.",JSON.stringify(Object.keys(o._getXhrs(t))),JSON.stringify(o._getFileState(t).chunking.inProgress))),qq.each(o._getXhrs(t),function(e,n){i(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ",t,e,n.readyState)),n.abort(),n._cancelled=!0}),o.moveInProgressToRemaining(t),c.free(t,!0)),l.onAutoRetry(t,a,q,r)||p.cleanup(t,q,r))},hasMoreParts:function(e){return!!o._getFileState(e).chunking.remaining.length},nextPart:function(e){var t=o._getFileState(e).chunking.remaining.shift();return t>=o._getTotalChunks(e)&&(t=null),t},reset:function(e){i("Server or callback has ordered chunking effort to be restarted on next attempt for item ID "+e,"error"),o._maybeDeletePersistedChunkData(e),o.reevaluateChunking(e),o._getFileState(e).loaded=0},sendNext:function(e){var t=l.getSize(e),n=l.getName(e),r=u.nextPart(e),a=o._getChunkData(e,r),d=o._getFileState(e).attemptingResume,q=o._getFileState(e).chunking.inProgress||[];null==o._getFileState(e).loaded&&(o._getFileState(e).loaded=0),d&&l.onResume(e,n,a)===!1&&(u.reset(e),r=u.nextPart(e),a=o._getChunkData(e,r),d=!1),null==r&&0===q.length?u.finalize(e):(i(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.",e,r,a.start+1,a.end,t)),l.onUploadChunk(e,n,o._getChunkDataForCallback(a)),q.push(r),o._getFileState(e).chunking.inProgress=q,s&&c.open(e,r),s&&c.available()&&o._getFileState(e).chunking.remaining.length&&u.sendNext(e),0===a.blob.size?(i(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.",r,e),"error"),u.handleFailure(r,e,"File is no longer available",null)):o.uploadChunk(e,r,d).then(function(t,n){i("Chunked upload request succeeded for "+e+", chunk "+r),o.clearCachedChunk(e,r);var a=o._getFileState(e).chunking.inProgress||[],s=p.normalizeResponse(t,!0),l=qq.indexOf(a,r);i(qq.format("Chunk {} for file {} uploaded successfully.",r,e)),u.done(e,r,s,n),l>=0&&a.splice(l,1),o._maybePersistChunkedState(e),u.hasMoreParts(e)||0!==a.length?u.hasMoreParts(e)?u.sendNext(e):i(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}",e,JSON.stringify(a))):u.finalize(e)},function(t,n){u.handleFailure(r,e,t,n)}).done(function(){o.clearXhr(e,r)}))}},c={_open:[],_openChunks:{},_waiting:[],available:function(){var e=l.maxConnections,t=0,n=0;return qq.each(c._openChunks,function(e,i){t++,n+=i.length}),e-(c._open.length-t+n)},free:function(e,t){var n,r=!t,a=qq.indexOf(c._waiting,e),s=qq.indexOf(c._open,e);delete c._openChunks[e],p.getProxyOrBlob(e)instanceof qq.BlobProxy&&(i("Generated blob upload has ended for "+e+", disposing generated blob."),delete o._getFileState(e).file),a>=0?c._waiting.splice(a,1):r&&s>=0&&(c._open.splice(s,1),n=c._waiting.shift(),n>=0&&(c._open.push(n),p.start(n)))},getWaitingOrConnected:function(){var e=[];return qq.each(c._openChunks,function(t,n){n&&n.length&&e.push(parseInt(t))}),qq.each(c._open,function(t,n){c._openChunks[n]||e.push(parseInt(n))}),e=e.concat(c._waiting)},isUsingConnection:function(e){return qq.indexOf(c._open,e)>=0},open:function(e,t){return null==t&&c._waiting.push(e),!!c.available()&&(null==t?(c._waiting.pop(),c._open.push(e)):!function(){var n=c._openChunks[e]||[];n.push(t),c._openChunks[e]=n}(),!0)},reset:function(){c._waiting=[],c._open=[]}},d={send:function(e,t){o._getFileState(e).loaded=0,i("Sending simple upload request for "+e),o.uploadFile(e).then(function(n,o){i("Simple upload request succeeded for "+e);var r=p.normalizeResponse(n,!0),a=l.getSize(e);l.onProgress(e,t,a,a),p.maybeNewUuid(e,r),p.cleanup(e,r,o)},function(n,o){i("Simple upload request failed for "+e);var r=p.normalizeResponse(n,!1);l.onAutoRetry(e,t,r,o)||p.cleanup(e,r,o)})}},p={cancel:function(e){i("Cancelling "+e),l.paramsStore.remove(e),c.free(e)},cleanup:function(e,t,n){var i=l.getName(e);l.onComplete(e,i,t,n),o._getFileState(e)&&o._clearXhrs&&o._clearXhrs(e),c.free(e)},getProxyOrBlob:function(e){return o.getProxy&&o.getProxy(e)||o.getFile&&o.getFile(e)},initHandler:function(){var e=t?qq[t]:qq.traditional,n=qq.supportedFeatures.ajaxUploading?"Xhr":"Form";o=new e[n+"UploadHandler"](l,{getDataByUuid:l.getDataByUuid,getName:l.getName,getSize:l.getSize,getUuid:l.getUuid,log:i,onCancel:l.onCancel,onProgress:l.onProgress,onUuidChanged:l.onUuidChanged}),o._removeExpiredChunkingRecords&&o._removeExpiredChunkingRecords()},isDeferredEligibleForUpload:function(e){return l.isQueued(e)},maybeDefer:function(e,t){return t&&!o.getFile(e)&&t instanceof qq.BlobProxy?(l.onUploadPrep(e),i("Attempting to generate a blob on-demand for "+e),t.create().then(function(t){i("Generated an on-demand blob for "+e),o.updateBlob(e,t),l.setSize(e,t.size),o.reevaluateChunking(e),p.maybeSendDeferredFiles(e)},function(t){var o={};t&&(o.error=t),i(qq.format("Failed to generate blob for ID {}. Error message: {}.",e,t),"error"),l.onComplete(e,l.getName(e),qq.extend(o,n),null),p.maybeSendDeferredFiles(e),c.free(e)}),!1):p.maybeSendDeferredFiles(e)},maybeSendDeferredFiles:function(e){var t=l.getIdsInProxyGroup(e),n=!1;return t&&t.length?(i("Maybe ready to upload proxy group file "+e),qq.each(t,function(t,i){if(p.isDeferredEligibleForUpload(i)&&o.getFile(i))n=i===e,p.now(i);else if(p.isDeferredEligibleForUpload(i))return!1})):(n=!0,p.now(e)),n},maybeNewUuid:function(e,t){void 0!==t.newUuid&&l.onUuidChanged(e,t.newUuid)},normalizeResponse:function(e,t){var n=e;return qq.isObject(e)||(n={},qq.isString(e)&&!t&&(n.error=e)),n.success=t,n},now:function(e){var t=l.getName(e);if(!r.isValid(e))throw new qq.Error(e+" is not a valid file ID to upload!");l.onUpload(e,t),a&&o._shouldChunkThisFile(e)?u.sendNext(e):d.send(e,t)},start:function(e){var t=p.getProxyOrBlob(e);return t?p.maybeDefer(e,t):(p.now(e),!0)}};qq.extend(this,{add:function(e,t){o.add.apply(this,arguments)},upload:function(e){return!!c.open(e)&&p.start(e)},retry:function(e){return s&&(o._getFileState(e).temp.ignoreFailure=!1),c.isUsingConnection(e)?p.start(e):r.upload(e)},cancel:function(e){var t=o.cancel(e);qq.isGenericPromise(t)?t.then(function(){p.cancel(e)}):t!==!1&&p.cancel(e)},cancelAll:function(){var e,t=c.getWaitingOrConnected();if(t.length)for(e=t.length-1;e>=0;e--)r.cancel(t[e]);c.reset()},getFile:function(e){return o.getProxy&&o.getProxy(e)?o.getProxy(e).referenceBlob:o.getFile&&o.getFile(e);
+},isProxied:function(e){return!(!o.getProxy||!o.getProxy(e))},getInput:function(e){if(o.getInput)return o.getInput(e)},reset:function(){i("Resetting upload handler"),r.cancelAll(),c.reset(),o.reset()},expunge:function(e){if(r.isValid(e))return o.expunge(e)},isValid:function(e){return o.isValid(e)},getResumableFilesData:function(){return o.getResumableFilesData?o.getResumableFilesData():[]},getThirdPartyFileId:function(e){if(r.isValid(e))return o.getThirdPartyFileId(e)},pause:function(e){return!!(r.isResumable(e)&&o.pause&&r.isValid(e)&&o.pause(e))&&(c.free(e),o.moveInProgressToRemaining(e),!0)},isResumable:function(e){return!!o.isResumable&&o.isResumable(e)}}),qq.extend(l,e),i=l.log,a=l.chunking.enabled&&qq.supportedFeatures.chunking,s=a&&l.chunking.concurrent.enabled,n=function(){var e={};return e[l.preventRetryParam]=!0,e}(),p.initHandler()},qq.WindowReceiveMessage=function(e){"use strict";var t={log:function(e,t){}},n={};qq.extend(t,e),qq.extend(this,{receiveMessage:function(e,t){var i=function(e){t(e.data)};window.postMessage?n[e]=qq(window).attach("message",i):log("iframe message passing not supported in this browser!","error")},stopReceivingMessages:function(e){if(window.postMessage){var t=n[e];t&&t()}}})},qq.FormUploadHandler=function(e){"use strict";function t(e){delete c[e],p&&(clearTimeout(d[e]),delete d[e],m.stopReceivingMessages(e));var t=document.getElementById(a._getIframeName(e));t&&(t.setAttribute("src","javascript:false;"),qq(t).remove())}function n(e){return e.split("_")[0]}function i(e){var t=qq.toElement("");return t.setAttribute("id",e),t.style.display="none",document.body.appendChild(t),t}function o(e,t){var i=e.id,o=n(i),r=h(o);u[r]=t,c[o]=qq(e).attach("load",function(){a.getInput(o)&&(f("Received iframe load event for CORS upload request (iframe name "+i+")"),d[i]=setTimeout(function(){var e="No valid message received from loaded iframe for iframe name "+i;f(e,"error"),t({error:e})},1e3))}),m.receiveMessage(i,function(e){f("Received the following window message: '"+e+"'");var t,o=(n(i),a._parseJsonResponse(e)),r=o.uuid;r&&u[r]?(f("Handling response for iframe name "+i),clearTimeout(d[i]),delete d[i],a._detachLoadEvent(i),t=u[r],delete u[r],m.stopReceivingMessages(i),t(o)):r||f("'"+e+"' does not contain a UUID - ignoring.")})}var r=e.options,a=this,s=e.proxy,l=qq.getUniqueId(),u={},c={},d={},p=r.isCors,q=r.inputName,h=s.getUuid,f=s.log,m=new qq.WindowReceiveMessage({log:f});qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,n){e.add(t,{input:n}),n.setAttribute("name",q),n.parentNode&&qq(n).remove()},expunge:function(n){t(n),e.expunge(n)},isValid:function(t){return e.isValid(t)&&void 0!==a._getFileState(t).input}}}),qq.extend(this,{getInput:function(e){return a._getFileState(e).input},_attachLoadEvent:function(e,t){var n;p?o(e,t):c[e.id]=qq(e).attach("load",function(){if(f("Received response for "+e.id),e.parentNode){try{if(e.contentDocument&&e.contentDocument.body&&"false"==e.contentDocument.body.innerHTML)return}catch(e){f("Error when attempting to access iframe during handling of upload response ("+e.message+")","error"),n={success:!1}}t(n)}})},_createIframe:function(e){var t=a._getIframeName(e);return i(t)},_detachLoadEvent:function(e){void 0!==c[e]&&(c[e](),delete c[e])},_getIframeName:function(e){return e+"_"+l},_initFormForUpload:function(e){var t=e.method,n=e.endpoint,i=e.params,o=e.paramsInBody,r=e.targetName,a=qq.toElement(""),s=n;return o?qq.obj2Inputs(i,a):s=qq.obj2url(i,n),a.setAttribute("action",s),a.setAttribute("target",r),a.style.display="none",document.body.appendChild(a),a},_parseJsonResponse:function(e){var t={};try{t=qq.parseJson(e)}catch(e){f("Error when attempting to parse iframe upload response ("+e.message+")","error")}return t}})},qq.XhrUploadHandler=function(e){"use strict";function t(e){qq.each(n._getXhrs(e),function(t,i){var o=n._getAjaxRequester(e,t);i.onreadystatechange=null,i.upload.onprogress=null,i.abort(),o&&o.canceled&&o.canceled(e)})}var n=this,i=e.options.namespace,o=e.proxy,r=e.options.chunking,a=e.options.resume,s=r&&e.options.chunking.enabled&&qq.supportedFeatures.chunking,l=a&&e.options.resume.enabled&&s&&qq.supportedFeatures.resume,u=o.getName,c=o.getSize,d=o.getUuid,p=o.getEndpoint,q=o.getDataByUuid,h=o.onUuidChanged,f=o.onProgress,m=o.log;qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,i){if(qq.isFile(i)||qq.isBlob(i))e.add(t,{file:i});else{if(!(i instanceof qq.BlobProxy))throw new Error("Passed obj is not a File, Blob, or proxy");e.add(t,{proxy:i})}n._initTempState(t),l&&n._maybePrepareForResume(t)},expunge:function(i){t(i),n._maybeDeletePersistedChunkData(i),n._clearXhrs(i),e.expunge(i)}}}),qq.extend(this,{clearCachedChunk:function(e,t){delete n._getFileState(e).temp.cachedChunks[t]},clearXhr:function(e,t){var i=n._getFileState(e).temp;i.xhrs&&delete i.xhrs[t],i.ajaxRequesters&&delete i.ajaxRequesters[t]},finalizeChunks:function(e,t){var i=n._getTotalChunks(e)-1,o=n._getXhr(e,i);return t?(new qq.Promise).success(t(o),o):(new qq.Promise).success({},o)},getFile:function(e){return n.isValid(e)&&n._getFileState(e).file},getProxy:function(e){return n.isValid(e)&&n._getFileState(e).proxy},getResumableFilesData:function(){var e=[];return n._iterateResumeRecords(function(t,i){n.moveInProgressToRemaining(null,i.chunking.inProgress,i.chunking.remaining);var o={name:i.name,remaining:i.chunking.remaining,size:i.size,uuid:i.uuid};i.key&&(o.key=i.key),e.push(o)}),e},isResumable:function(e){return!!r&&n.isValid(e)&&!n._getFileState(e).notResumable},moveInProgressToRemaining:function(e,t,i){var o=t||n._getFileState(e).chunking.inProgress,r=i||n._getFileState(e).chunking.remaining;o&&(m(qq.format("Moving these chunks from in-progress {}, to remaining.",JSON.stringify(o))),o.reverse(),qq.each(o,function(e,t){r.unshift(t)}),o.length=0)},pause:function(e){if(n.isValid(e))return m(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.",e,u(e))),n._getFileState(e).paused=!0,t(e),!0},reevaluateChunking:function(e){if(r&&n.isValid(e)){var t,i,o=n._getFileState(e);if(delete o.chunking,o.chunking={},t=n._getTotalChunks(e),t>1||r.mandatory){for(o.chunking.enabled=!0,o.chunking.parts=t,o.chunking.remaining=[],i=0;i=o?o:s+i,u=n._getTotalChunks(e),d=this._getFileState(e).temp.cachedChunks,p=d[t]||qq.sliceBlob(a,s,l);return d[t]=p,{part:t,start:s,end:l,count:u,blob:p,size:l-s}},_getChunkDataForCallback:function(e){return{partIndex:e.part,startByte:e.start+1,endByte:e.end,totalParts:e.count}},_getLocalStorageId:function(e){var t="5.0",n=u(e),o=c(e),a=r.partSize,s=p(e);return qq.format("qq{}resume{}-{}-{}-{}-{}",i,t,n,o,a,s)},_getMimeType:function(e){return n.getFile(e).type},_getPersistableData:function(e){return n._getFileState(e).chunking},_getTotalChunks:function(e){if(r){var t=c(e),n=r.partSize;return Math.ceil(t/n)}},_getXhr:function(e,t){var i=null==t?-1:t;return n._getFileState(e).temp.xhrs[i]},_getXhrs:function(e){return n._getFileState(e).temp.xhrs},_iterateResumeRecords:function(e){l&&qq.each(localStorage,function(t,n){if(0===t.indexOf(qq.format("qq{}resume",i))){var o=JSON.parse(n);e(t,o)}})},_initTempState:function(e){n._getFileState(e).temp={ajaxRequesters:{},chunkProgress:{},xhrs:{},cachedChunks:{}}},_markNotResumable:function(e){n._getFileState(e).notResumable=!0},_maybeDeletePersistedChunkData:function(e){var t;return!!(l&&n.isResumable(e)&&(t=n._getLocalStorageId(e),t&&localStorage.getItem(t)))&&(localStorage.removeItem(t),!0)},_maybePrepareForResume:function(e){var t,i,o=n._getFileState(e);l&&void 0===o.key&&(t=n._getLocalStorageId(e),i=localStorage.getItem(t),i&&(i=JSON.parse(i),q(i.uuid)?n._markNotResumable(e):(m(qq.format("Identified file with ID {} and name of {} as resumable.",e,u(e))),h(e,i.uuid),o.key=i.key,o.chunking=i.chunking,o.loaded=i.loaded,o.attemptingResume=!0,n.moveInProgressToRemaining(e))))},_maybePersistChunkedState:function(e){var t,i,o=n._getFileState(e);if(l&&n.isResumable(e)){t=n._getLocalStorageId(e),i={name:u(e),size:c(e),uuid:d(e),key:o.key,chunking:o.chunking,loaded:o.loaded,lastUpdated:Date.now()};try{localStorage.setItem(t,JSON.stringify(i))}catch(t){m(qq.format("Unable to save resume data for '{}' due to error: '{}'.",e,t.toString()),"warn")}}},_registerProgressHandler:function(e,t,i){var o=n._getXhr(e,t),r=u(e),a={simple:function(t,n){var i=c(e);t===n?f(e,r,i,i):f(e,r,t>=i?i-1:t,i)},chunked:function(o,a){var s=n._getFileState(e).temp.chunkProgress,l=n._getFileState(e).loaded,u=o,d=a,p=c(e),q=u-(d-i),h=l;s[t]=q,qq.each(s,function(e,t){h+=t}),f(e,r,h,p)}};o.upload.onprogress=function(e){if(e.lengthComputable){var t=null==i?"simple":"chunked";a[t](e.loaded,e.total)}}},_registerXhr:function(e,t,i,o){var r=null==t?-1:t,a=n._getFileState(e).temp;return a.xhrs=a.xhrs||{},a.ajaxRequesters=a.ajaxRequesters||{},a.xhrs[r]=i,o&&(a.ajaxRequesters[r]=o),i},_removeExpiredChunkingRecords:function(){var e=a.recordsExpireIn;n._iterateResumeRecords(function(t,n){var i=new Date(n.lastUpdated);i.setDate(i.getDate()+e),i.getTime()<=Date.now()&&(m("Removing expired resume record with key "+t),localStorage.removeItem(t))})},_shouldChunkThisFile:function(e){var t=n._getFileState(e);return t.chunking||n.reevaluateChunking(e),t.chunking.enabled}})},qq.DeleteFileAjaxRequester=function(e){"use strict";function t(){return"POST"===i.method.toUpperCase()?{_method:"DELETE"}:{}}var n,i={method:"DELETE",uuidParamName:"qquuid",endpointStore:{},maxConnections:3,customHeaders:function(e){return{}},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onDelete:function(e){},onDeleteComplete:function(e,t,n){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["POST","DELETE"],method:i.method,endpointStore:i.endpointStore,paramsStore:i.paramsStore,mandatedParams:t(),maxConnections:i.maxConnections,customHeaders:function(e){return i.customHeaders.get(e)},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete,cors:i.cors})),qq.extend(this,{sendDelete:function(e,t,o){var r=o||{};i.log("Submitting delete file request for "+e),"DELETE"===i.method?n.initTransport(e).withPath(t).withParams(r).send():(r[i.uuidParamName]=t,n.initTransport(e).withParams(r).send())}})},function(){function e(e){var t,n=e.naturalWidth,i=e.naturalHeight,o=document.createElement("canvas");return n*i>1048576&&(o.width=o.height=1,t=o.getContext("2d"),t.drawImage(e,-n+1,0),0===t.getImageData(0,0,1,1).data[3])}function t(e,t,n){var i,o,r,a,s=document.createElement("canvas"),l=0,u=n,c=n;for(s.width=1,s.height=n,i=s.getContext("2d"),i.drawImage(e,0,0),o=i.getImageData(0,0,1,n).data;c>l;)r=o[4*(c-1)+3],0===r?u=c:l=c,c=u+l>>1;return a=c/n,0===a?1:a}function n(e,t,n,i){var r=document.createElement("canvas"),a=n.mime||"image/jpeg",s=new qq.Promise;return o(e,t,r,n,i).then(function(){s.success(r.toDataURL(a,n.quality||.8))}),s}function i(e){var t=5241e3;if(!qq.ios())throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");if(e.origHeight*e.origWidth>t)return{newHeight:Math.round(Math.sqrt(t*(e.origHeight/e.origWidth))),newWidth:Math.round(Math.sqrt(t*(e.origWidth/e.origHeight)))}}function o(n,o,s,l,u){var c,d=n.naturalWidth,p=n.naturalHeight,q=l.width,h=l.height,f=s.getContext("2d"),m=new qq.Promise;return f.save(),l.resize?r({blob:o,canvas:s,image:n,imageHeight:p,imageWidth:d,orientation:l.orientation,resize:l.resize,targetHeight:h,targetWidth:q}):(qq.supportedFeatures.unlimitedScaledImageSize||(c=i({origWidth:q,origHeight:h}),c&&(qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h",q,h,c.newWidth,c.newHeight),"warn"),q=c.newWidth,h=c.newHeight)),a(s,q,h,l.orientation),qq.ios()?!function(){e(n)&&(d/=2,p/=2);var i,o,r,a=1024,s=document.createElement("canvas"),l=u?t(n,d,p):1,c=Math.ceil(a*q/d),m=Math.ceil(a*h/p/l),g=0,_=0;for(s.width=s.height=a,i=s.getContext("2d");gc&&(l=c,u=s*l/a<<0),d&&u>d&&(u=d,l=a*u/s<<0),i={width:l,height:u},qq.each(t,function(e,t){i[e]=t}),"img"===q?!function(){var t=e.src;n(r.srcImage,r.blob,i,p).then(function(n){e.src=n,t===e.src&&e.onload()})}():"canvas"===q&&o(this.srcImage,this.blob,e,i,p),void("function"==typeof this.onrender&&this.onrender(e)))},qq.MegaPixImage=s}(),qq.ImageGenerator=function(e){"use strict";function t(e){return"img"===e.tagName.toLowerCase()}function n(e){return"canvas"===e.tagName.toLowerCase()}function i(){return void 0!==(new Image).crossOrigin}function o(){var e=document.createElement("canvas");return e.getContext&&e.getContext("2d")}function r(e){var t=e.split("/"),n=t[t.length-1].split("?")[0],i=qq.getExtension(n);switch(i=i&&i.toLowerCase()){case"jpeg":case"jpg":return"image/jpeg";case"png":return"image/png";case"bmp":return"image/bmp";case"gif":return"image/gif";case"tiff":case"tif":return"image/tiff"}}function a(e){var t,n,i,o=document.createElement("a");return o.href=e,t=o.protocol,i=o.port,n=o.hostname,t.toLowerCase()!==window.location.protocol.toLowerCase()||(n.toLowerCase()!==window.location.hostname.toLowerCase()||i!==window.location.port&&!qq.ie())}function s(t,n){t.onload=function(){t.onload=null,t.onerror=null,n.success(t)},t.onerror=function(){t.onload=null,t.onerror=null,e("Problem drawing thumbnail!","error"),n.failure(t,"Problem drawing thumbnail!")}}function l(e,t){e.qqImageRendered=function(){t.success(e)}}function u(i,o){var r=t(i)||n(i);return t(i)?s(i,o):n(i)?l(i,o):(o.failure(i),e(qq.format("Element container of type {} is not supported!",i.tagName),"error")),r}function c(t,n,i){var o=new qq.Promise,r=new qq.Identify(t,e),a=i.maxSize,s=null==i.orient||i.orient,l=function(){n.onerror=null,n.onload=null,e("Could not render preview, file may be too large!","error"),o.failure(n,"Browser cannot render image!")};return r.isPreviewable().then(function(r){var c={parse:function(){return(new qq.Promise).success()}},d=s?new qq.Exif(t,e):c,p=new qq.MegaPixImage(t,l);u(n,o)&&d.parse().then(function(e){var t=e&&e.Orientation;p.render(n,{maxWidth:a,maxHeight:a,orientation:t,mime:r,resize:i.customResizeFunction})},function(t){e(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.",t)),p.render(n,{maxWidth:a,maxHeight:a,mime:r,resize:i.customResizeFunction})})},function(){e("Not previewable"),o.failure(n,"Not previewable")}),o}function d(e,t,n,i,o){var s=new Image,l=new qq.Promise;u(s,l),a(e)&&(s.crossOrigin="anonymous"),s.src=e,l.then(function(){u(t,n);var a=new qq.MegaPixImage(s);a.render(t,{maxWidth:i,maxHeight:i,mime:r(e),resize:o})},n.failure)}function p(e,t,n,i){u(t,n),qq(t).css({maxWidth:i+"px",maxHeight:i+"px"}),t.src=e}function q(e,r,s){var l=new qq.Promise,c=s.scale,q=c?s.maxSize:null;return c&&t(r)?o()?a(e)&&!i()?p(e,r,l,q):d(e,r,l,q):p(e,r,l,q):n(r)?d(e,r,l,q):u(r,l)&&(r.src=e),l}qq.extend(this,{generate:function(t,n,i){return qq.isString(t)?(e("Attempting to update thumbnail based on server response."),q(t,n,i||{})):(e("Attempting to draw client-side image preview."),c(t,n,i||{}))}}),this._testing={},this._testing.isImg=t,this._testing.isCanvas=n,this._testing.isCrossOrigin=a,this._testing.determineMimeOfFileName=r},qq.Exif=function(e,t){"use strict";function n(e){for(var t=0,n=0;e.length>0;)t+=parseInt(e.substring(0,2),16)*Math.pow(2,n),e=e.substring(2,e.length),n+=8;return t}function i(t,n){var o=t,r=n;return void 0===o&&(o=2,r=new qq.Promise),qq.readBlobToHex(e,o,4).then(function(e){var t,n=/^ffe([0-9])/.exec(e);n?"1"!==n[1]?(t=parseInt(e.slice(4,8),16),i(o+t+2,r)):r.success(o):r.failure("No EXIF header to be found!")}),r}function o(){var t=new qq.Promise;return qq.readBlobToHex(e,0,6).then(function(e){0!==e.indexOf("ffd8")?t.failure("Not a valid JPEG!"):i().then(function(e){t.success(e)},function(e){t.failure(e)})}),t}function r(t){var n=new qq.Promise;return qq.readBlobToHex(e,t+10,2).then(function(e){n.success("4949"===e)}),n}function a(t,i){var o=new qq.Promise;return qq.readBlobToHex(e,t+18,2).then(function(e){return i?o.success(n(e)):void o.success(parseInt(e,16))}),o}function s(t,n){var i=t+20,o=12*n;return qq.readBlobToHex(e,i,o)}function l(e){for(var t=[],n=0;n+24<=e.length;)t.push(e.slice(n,n+24)),n+=24;return t}function u(e,t){var i=16,o=qq.extend([],c),r={};return qq.each(t,function(t,a){var s,l,u,c=a.slice(0,4),p=e?n(c):parseInt(c,16),q=o.indexOf(p);if(q>=0&&(l=d[p].name,u=d[p].bytes,s=a.slice(i,i+2*u),r[l]=e?n(s):parseInt(s,16),o.splice(q,1)),0===o.length)return!1}),r}var c=[274],d={274:{name:"Orientation",bytes:2}};qq.extend(this,{parse:function(){var n=new qq.Promise,i=function(e){t(qq.format("EXIF header parse failed: '{}' ",e)),n.failure(e)};return o().then(function(o){t(qq.format("Moving forward with EXIF header parsing for '{}'",void 0===e.name?"blob":e.name)),r(o).then(function(e){t(qq.format("EXIF Byte order is {} endian",e?"little":"big")),a(o,e).then(function(r){t(qq.format("Found {} APP1 directory entries",r)),s(o,r).then(function(i){var o=l(i),r=u(e,o);t("Successfully parsed some EXIF tags"),n.success(r)},i)},i)},i)},i),n}}),this._testing={},this._testing.parseLittleEndian=n},qq.Identify=function(e,t){"use strict";function n(e,t){var n=!1,i=[].concat(e);return qq.each(i,function(e,i){if(0===t.indexOf(i))return n=!0,!1}),n}qq.extend(this,{isPreviewable:function(){var i=this,o=new qq.Promise,r=!1,a=void 0===e.name?"blob":e.name;return t(qq.format("Attempting to determine if {} can be rendered in this browser",a)),t("First pass: check type attribute of blob object."),this.isPreviewableSync()?(t("Second pass: check for magic bytes in file header."),qq.readBlobToHex(e,0,4).then(function(e){qq.each(i.PREVIEWABLE_MIME_TYPES,function(t,i){if(n(i,e))return("image/tiff"!==t||qq.supportedFeatures.tiffPreviews)&&(r=!0,o.success(t)),!1}),t(qq.format("'{}' is {} able to be rendered in this browser",a,r?"":"NOT")),r||o.failure()},function(){t("Error reading file w/ name '"+a+"'. Not able to be rendered in this browser."),o.failure()})):o.failure(),o},isPreviewableSync:function(){var n=e.type,i=qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES),n)>=0,o=!1,r=void 0===e.name?"blob":e.name;return i&&(o="image/tiff"!==n||qq.supportedFeatures.tiffPreviews),!o&&t(r+" is not previewable in this browser per the blob's type attr"),o}})},qq.Identify.prototype.PREVIEWABLE_MIME_TYPES={"image/jpeg":"ffd8ff","image/gif":"474946","image/png":"89504e","image/bmp":"424d","image/tiff":["49492a00","4d4d002a"]},qq.ImageValidation=function(e,t){"use strict";function n(e){var t=!1;return qq.each(e,function(e,n){if(n>0)return t=!0,!1}),t}function i(){var n=new qq.Promise;return new qq.Identify(e,t).isPreviewable().then(function(){var i=new Image,o=window.URL&&window.URL.createObjectURL?window.URL:window.webkitURL&&window.webkitURL.createObjectURL?window.webkitURL:null;o?(i.onerror=function(){t("Cannot determine dimensions for image. May be too large.","error"),n.failure()},i.onload=function(){n.success({width:this.width,height:this.height})},i.src=o.createObjectURL(e)):(t("No createObjectURL function available to generate image URL!","error"),n.failure())},n.failure),n}function o(e,t){var n;return qq.each(e,function(e,i){if(i>0){var o=/(max|min)(Width|Height)/.exec(e),r=o[2].charAt(0).toLowerCase()+o[2].slice(1),a=t[r];switch(o[1]){case"min":if(ai)return n=e,!1}}}),n}this.validate=function(e){var r=new qq.Promise;return t("Attempting to validate image."),n(e)?i().then(function(t){var n=o(e,t);n?r.failure(n):r.success()},r.success):r.success(),r}},qq.Session=function(e){"use strict";function t(e){return!!qq.isArray(e)||void i.log("Session response is not an array.","error")}function n(e,n,o,r){var a=!1;n=n&&t(e),n&&qq.each(e,function(e,t){if(null==t.uuid)a=!0,i.log(qq.format("Session response item {} did not include a valid UUID - ignoring.",e),"error");else if(null==t.name)a=!0,i.log(qq.format("Session response item {} did not include a valid name - ignoring.",e),"error");else try{return i.addFileRecord(t),!0}catch(e){a=!0,i.log(e.message,"error")}return!1}),r[n&&!a?"success":"failure"](e,o)}var i={endpoint:null,params:{},customHeaders:{},cors:{},addFileRecord:function(e){},log:function(e,t){}};qq.extend(i,e,!0),this.refresh=function(){var e=new qq.Promise,t=function(t,i,o){n(t,i,o,e)},o=qq.extend({},i),r=new qq.SessionAjaxRequester(qq.extend(o,{onComplete:t}));return r.queryServer(),e}},qq.SessionAjaxRequester=function(e){"use strict";function t(e,t,n){var o=null;if(null!=t.responseText)try{o=qq.parseJson(t.responseText)}catch(e){i.log("Problem parsing session response: "+e.message,"error"),n=!0}i.onComplete(o,!n,t)}var n,i={endpoint:null,customHeaders:{},params:{},cors:{expected:!1,sendCredentials:!1},onComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",endpointStore:{get:function(){return i.endpoint}},customHeaders:i.customHeaders,log:i.log,onComplete:t,cors:i.cors})),qq.extend(this,{queryServer:function(){var e=qq.extend({},i.params);i.log("Session query request."),n.initTransport("sessionRefresh").withParams(e).withCacheBuster().send()}})},qq.Scaler=function(e,t){"use strict";var n=e.customResizer,i=e.sendOriginal,o=e.orient,r=e.defaultType,a=e.defaultQuality/100,s=e.failureText,l=e.includeExif,u=this._getSortedSizes(e.sizes);qq.extend(this,{enabled:qq.supportedFeatures.scaling&&u.length>0,getFileRecords:function(e,c,d){var p=this,q=[],h=d.blob?d.blob:d,f=new qq.Identify(h,t);return f.isPreviewableSync()?(qq.each(u,function(e,i){var u=p._determineOutputType({defaultType:r,requestedType:i.type,refType:h.type});q.push({uuid:qq.getUniqueId(),name:p._getName(c,{name:i.name,type:u,refType:h.type}),blob:new qq.BlobProxy(h,qq.bind(p._generateScaledImage,p,{customResizeFunction:n,maxSize:i.maxSize,orient:o,type:u,quality:a,failedText:s,includeExif:l,log:t}))})}),q.push({uuid:e,name:c,size:h.size,blob:i?h:null})):q.push({uuid:e,name:c,size:h.size,blob:h}),q},handleNewFile:function(e,t,n,i,o,r,a,s){var l=this,u=(e.qqButtonId||e.blob&&e.blob.qqButtonId,[]),c=null,d=s.addFileToHandler,p=s.uploadData,q=s.paramsStore,h=qq.getUniqueId();qq.each(l.getFileRecords(n,t,e),function(e,t){var n,i=t.size;t.blob instanceof qq.BlobProxy&&(i=-1),n=p.addFile({uuid:t.uuid,name:t.name,size:i,batchId:r,proxyGroupId:h}),t.blob instanceof qq.BlobProxy?u.push(n):c=n,t.blob?(d(n,t.blob),o.push({id:n,file:t.blob})):p.setStatus(n,qq.status.REJECTED)}),null!==c&&(qq.each(u,function(e,t){var n={qqparentuuid:p.retrieve({id:c}).uuid,qqparentsize:p.retrieve({id:c}).size};n[a]=p.retrieve({id:t}).uuid,p.setParentId(t,c),q.addReadOnly(t,n)}),u.length&&!function(){var e={};e[a]=p.retrieve({id:c}).uuid,q.addReadOnly(c,e)}())}})},qq.extend(qq.Scaler.prototype,{scaleImage:function(e,t,n){"use strict";if(!qq.supportedFeatures.scaling)throw new qq.Error("Scaling is not supported in this browser!");var i=new qq.Promise,o=n.log,r=n.getFile(e),a=n.uploadData.retrieve({id:e}),s=a&&a.name,l=a&&a.uuid,u={customResizer:t.customResizer,sendOriginal:!1,orient:t.orient,defaultType:t.type||null,defaultQuality:t.quality,failedToScaleText:"Unable to scale",sizes:[{name:"",maxSize:t.maxSize}]},c=new qq.Scaler(u,o);return qq.Scaler&&qq.supportedFeatures.imagePreviews&&r?qq.bind(function(){var t=c.getFileRecords(l,s,r)[0];t&&t.blob instanceof qq.BlobProxy?t.blob.create().then(i.success,i.failure):(o(e+" is not a scalable image!","error"),i.failure())},this)():(i.failure(),o("Could not generate requested scaled image for "+e+". Scaling is either not possible in this browser, or the file could not be located.","error")),i},_determineOutputType:function(e){"use strict";var t=e.requestedType,n=e.defaultType,i=e.refType;return n||t?t&&qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES),t)>=0?"image/tiff"===t?qq.supportedFeatures.tiffPreviews?t:n:t:n:"image/jpeg"!==i?"image/png":i},_getName:function(e,t){"use strict";var n=e.lastIndexOf("."),i=t.type||"image/png",o=t.refType,r="",a=qq.getExtension(e),s="";return t.name&&t.name.trim().length&&(s=" ("+t.name+")"),n>=0?(r=e.substr(0,n),o!==i&&(a=i.split("/")[1]),r+=s+"."+a):r=e+s,r},_getSortedSizes:function(e){"use strict";return e=qq.extend([],e),e.sort(function(e,t){return e.maxSize>t.maxSize?1:e.maxSize=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),n=e.split(",")[0].split(":")[1].split(";")[0],i=new ArrayBuffer(t.length),o=new Uint8Array(i),qq.each(t,function(e,t){o[e]=t.charCodeAt(0)}),this._createBlob(i,n)},_createBlob:function(e,t){"use strict";var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})}}),qq.ExifRestorer=function(){var e={};return e.KEY_STR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e.encode64=function(e){var t,n,i,o,r,a="",s="",l="",u=0;do t=e[u++],n=e[u++],s=e[u++],i=t>>2,o=(3&t)<<4|n>>4,r=(15&n)<<2|s>>6,l=63&s,isNaN(n)?r=l=64:isNaN(s)&&(l=64),a=a+this.KEY_STR.charAt(i)+this.KEY_STR.charAt(o)+this.KEY_STR.charAt(r)+this.KEY_STR.charAt(l),t=n=s="",i=o=r=l="";while(ue.length)break}return n},e.decode64=function(e){var t,n,i,o,r,a="",s="",l=0,u=[],c=/[^A-Za-z0-9\+\/\=]/g;if(c.exec(e))throw new Error("There were invalid base64 characters in the input text. Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");do i=this.KEY_STR.indexOf(e.charAt(l++)),o=this.KEY_STR.indexOf(e.charAt(l++)),r=this.KEY_STR.indexOf(e.charAt(l++)),s=this.KEY_STR.indexOf(e.charAt(l++)),t=i<<2|o>>4,n=(15&o)<<4|r>>2,a=(3&r)<<6|s,u.push(t),64!=r&&u.push(n),64!=s&&u.push(a),t=n=a="",i=o=r=s="";while(l=0)return n=!1,!1}),n},u=function(e){p(e,-1,-1),delete n[e]},c=function(e,t,n){(0===t.length||l(t,n))&&(s(o,o),this.reset())},d=function(e){var i=t(e);i>0&&(p(e,0,i),n[e]={loaded:0,total:i})},p=function(e,t,r){var a=n[e]?n[e].loaded:0,l=n[e]?n[e].total:0;t===-1&&r===-1?(i-=a,o-=l):(t&&(i+=t-a),r&&(o+=r-l)),s(i,o)};qq.extend(this,{onAllComplete:c,onStatusChange:function(e,t,n){n===qq.status.CANCELED||n===qq.status.REJECTED?u(e):n===qq.status.SUBMITTING&&d(e)},onIndividualProgress:function(e,t,i){p(e,t,i),n[e]={loaded:t,total:i}},onNewSize:function(e){d(e)},reset:function(){n={},i=0,o=0}})},qq.PasteSupport=function(e){"use strict";function t(e){return e.type&&0===e.type.indexOf("image/")}function n(){r=qq(o.targetElement).attach("paste",function(e){var n=e.clipboardData;n&&qq.each(n.items,function(e,n){if(t(n)){var i=n.getAsFile();o.callbacks.pasteReceived(i)}})})}function i(){r&&r()}var o,r;o={targetElement:null,callbacks:{log:function(e,t){},pasteReceived:function(e){}}},qq.extend(o,e),n(),qq.extend(this,{reset:function(){i()}})},qq.FormSupport=function(e,t,n){"use strict";function i(e){e.getAttribute("action")&&(s.newEndpoint=e.getAttribute("action"))}function o(e,t){return!(e.checkValidity&&!e.checkValidity())||(n("Form did not pass validation checks - will not upload.","error"),void t())}function r(e){var n=e.submit;
+qq(e).attach("submit",function(i){i=i||window.event,i.preventDefault?i.preventDefault():i.returnValue=!1,o(e,n)&&t()}),e.submit=function(){o(e,n)&&t()}}function a(e){return e&&(qq.isString(e)&&(e=document.getElementById(e)),e&&(n("Attaching to form element."),i(e),l&&r(e))),e}var s=this,l=e.interceptSubmit,u=e.element,c=e.autoUpload;qq.extend(this,{newEndpoint:null,newAutoUpload:c,attachedToForm:!1,getFormInputsAsObject:function(){return null==u?null:s._form2Obj(u)}}),u=a(u),this.attachedToForm=!!u},qq.extend(qq.FormSupport.prototype,{_form2Obj:function(e){"use strict";var t={},n=function(e){var t=["button","image","reset","submit"];return qq.indexOf(t,e.toLowerCase())<0},i=function(e){return qq.indexOf(["checkbox","radio"],e.toLowerCase())>=0},o=function(e){return!(!i(e.type)||e.checked)||e.disabled&&"hidden"!==e.type.toLowerCase()},r=function(e){var t=null;return qq.each(qq(e).children(),function(e,n){if("option"===n.tagName.toLowerCase()&&n.selected)return t=n.value,!1}),t};return qq.each(e.elements,function(e,i){if(!qq.isInput(i,!0)&&"textarea"!==i.tagName.toLowerCase()||!n(i.type)||o(i)){if("select"===i.tagName.toLowerCase()&&!o(i)){var a=r(i);null!==a&&(t[i.name]=a)}}else t[i.name]=i.value}),t}}),qq.azure=qq.azure||{},qq.azure.util=qq.azure.util||function(){"use strict";return{AZURE_PARAM_PREFIX:"x-ms-meta-",_paramNameMatchesAzureParameter:function(e){switch(e){case"Cache-Control":case"Content-Disposition":case"Content-Encoding":case"Content-MD5":case"x-ms-blob-content-encoding":case"x-ms-blob-content-disposition":case"x-ms-blob-content-md5":case"x-ms-blob-cache-control":return!0;default:return!1}},_getPrefixedParamName:function(e){return qq.azure.util._paramNameMatchesAzureParameter(e)?e:qq.azure.util.AZURE_PARAM_PREFIX+e},getParamsAsHeaders:function(e){var t={};return qq.each(e,function(e,n){var i=qq.azure.util._getPrefixedParamName(e),o=null;qq.isFunction(n)?o=String(n()):qq.isObject(n)?qq.extend(t,qq.azure.util.getParamsAsHeaders(n)):o=String(n),null!==o&&(qq.azure.util._paramNameMatchesAzureParameter(e)?t[i]=o:t[i]=encodeURIComponent(o))}),t},parseAzureError:function(e,t){var n,i,o=new DOMParser,r=o.parseFromString(e,"application/xml"),a=r.getElementsByTagName("Error")[0],s={};if(t("Received error response: "+e,"error"),a)return i=a.getElementsByTagName("Message")[0],i&&(s.message=i.textContent),n=a.getElementsByTagName("Code")[0],n&&(s.code=n.textContent),t("Parsed Azure error: "+JSON.stringify(s),"error"),s}}}(),function(){"use strict";qq.nonTraditionalBasePublicApi={setUploadSuccessParams:function(e,t){this._uploadSuccessParamsStore.set(e,t)},setUploadSuccessEndpoint:function(e,t){this._uploadSuccessEndpointStore.set(e,t)}},qq.nonTraditionalBasePrivateApi={_onComplete:function(e,t,n,i){var o,r,a=!!n.success,s=this,l=arguments,u=this._uploadSuccessEndpointStore.get(e),c=this._options.uploadSuccess.customHeaders,d=this._options.uploadSuccess.method,p=this._options.cors,q=new qq.Promise,h=this._uploadSuccessParamsStore.get(e),f=this._paramsStore.get(e),m=function(t){delete s._failedSuccessRequestCallbacks[e],qq.extend(n,t),qq.FineUploaderBasic.prototype._onComplete.apply(s,l),q.success(t)},g=function(r){var a=o;qq.extend(n,r),n&&n.reset&&(a=null),a?s._failedSuccessRequestCallbacks[e]=a:delete s._failedSuccessRequestCallbacks[e],s._onAutoRetry(e,t,n,i,a)||(qq.FineUploaderBasic.prototype._onComplete.apply(s,l),q.failure(r))};return a&&u?(r=new qq.UploadSuccessAjaxRequester({endpoint:u,method:d,customHeaders:c,cors:p,log:qq.bind(this.log,this)}),qq.extend(h,s._getEndpointSpecificParams(e,n,i),!0),f&&qq.extend(h,f,!0),o=qq.bind(function(){r.sendSuccessRequest(e,h).then(m,g)},s),o(),q):qq.FineUploaderBasic.prototype._onComplete.apply(this,arguments)},_manualRetry:function(e){var t=this._failedSuccessRequestCallbacks[e];return qq.FineUploaderBasic.prototype._manualRetry.call(this,e,t)}}}(),function(){"use strict";qq.azure.FineUploaderBasic=function(e){if(!qq.supportedFeatures.ajaxUploading)throw new qq.Error("Uploading directly to Azure is not possible in this browser.");var t={signature:{endpoint:null,customHeaders:{}},blobProperties:{name:"uuid"},uploadSuccess:{endpoint:null,method:"POST",params:{},customHeaders:{}},chunking:{partSize:4e6,minFileSize:4000001}};qq.extend(t,e,!0),qq.FineUploaderBasic.call(this,t),this._uploadSuccessParamsStore=this._createStore(this._options.uploadSuccess.params),this._uploadSuccessEndpointStore=this._createStore(this._options.uploadSuccess.endpoint),this._failedSuccessRequestCallbacks={},this._cannedBlobNames={}},qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,{getBlobName:function(e){return null==this._cannedBlobNames[e]?this._handler.getThirdPartyFileId(e):this._cannedBlobNames[e]},_getEndpointSpecificParams:function(e){return{blob:this.getBlobName(e),uuid:this.getUuid(e),name:this.getName(e),container:this._endpointStore.get(e)}},_createUploadHandler:function(){return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,{signature:this._options.signature,onGetBlobName:qq.bind(this._determineBlobName,this),deleteBlob:qq.bind(this._deleteBlob,this,!0)},"azure")},_determineBlobName:function(e){var t=this._options.blobProperties.name,n=this.getUuid(e),i=this.getName(e),o=qq.getExtension(i),r=n;if(!qq.isString(t))return t.call(this,e);switch(t){case"uuid":return void 0!==o&&(r+="."+o),(new qq.Promise).success(r);case"filename":return(new qq.Promise).success(i);default:return new qq.Promise.failure("Invalid blobName option value - "+t)}},_addCannedFile:function(e){var t;if(null==e.blobName)throw new qq.Error("Did not find blob name property in server session response. This is required!");return t=qq.FineUploaderBasic.prototype._addCannedFile.apply(this,arguments),this._cannedBlobNames[t]=e.blobName,t},_deleteBlob:function(e,t){var n=this,i={},o={get:function(e){return n._endpointStore.get(e)+"/"+n.getBlobName(e)}},r={get:function(e){return i[e]}},a=function(e,t){i[e]=t,l.send(e)},s=function(t,i,o){e?(n.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS","error"),qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t))):(n._onDeleteComplete(t,o,!0),n._options.callbacks.onDeleteComplete(t,o,!0))},l=new qq.azure.DeleteBlob({endpointStore:r,log:qq.bind(n.log,n),onDelete:function(e){n._onDelete(e),n._options.callbacks.onDelete(e)},onDeleteComplete:function(t,o,r){delete i[t],r&&(e?n.log("Will cancel upload, but failed to remove uncommitted parts from Azure.","error"):qq.azure.util.parseAzureError(o.responseText,qq.bind(n.log,n))),e?(qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t)),n.log("Deleted uncommitted blob chunks for "+t)):(n._onDeleteComplete(t,o,r),n._options.callbacks.onDeleteComplete(t,o,r))}}),u=new qq.azure.GetSas({cors:this._options.cors,customHeaders:this._options.signature.customHeaders,endpointStore:{get:function(){return n._options.signature.endpoint}},restRequestVerb:l.method,log:qq.bind(n.log,n)});u.request(t,o.get(t)).then(qq.bind(a,n,t),qq.bind(s,n,t))},_createDeleteHandler:function(){var e=this;return{sendDelete:function(t,n){e._deleteBlob(!1,t)}}}})}(),qq.azure.XhrUploadHandler=function(e,t){"use strict";function n(e){var t=new qq.Promise;return o(e).then(function(n){var i=a._getMimeType(e),o=a._getPersistableData(e).blockIdEntries;b.putBlockList.send(e,n,o,i,function(t){a._registerXhr(e,null,t,b.putBlockList)}).then(function(n){s("Success combining chunks for id "+e),t.success({},n)},function(n){s("Attempt to combine chunks failed for id "+e,"error"),r(n,t)})},t.failure),t}function i(e){var t=u.get(e),n=new qq.Promise,i=function(i){a._setThirdPartyFileId(e,i),n.success(t+"/"+i)},o=function(e){n.failure(e)};return f(e).then(i,o),n}function o(e,t){var n=null==t?e:e+"."+t,o=new qq.Promise,r=function(e){s("GET SAS request succeeded."),o.success(e)},a=function(e,t){s("GET SAS request failed: "+e,"error"),o.failure({error:"Problem communicating with local server"},t)},l=function(e){b.getSasForPutBlobOrBlock.request(n,e).then(r,a)},u=function(t){s(qq.format("Failed to determine blob name for ID {} - {}",e,t),"error"),o.failure({error:t})};return i(e).then(l,u),o}function r(e,t){var n=qq.azure.util.parseAzureError(e.responseText,s),i="Problem sending file to Azure";t.failure({error:i,azureError:n&&n.message,reset:403===e.status})}var a=this,s=t.log,l=e.cors,u=e.endpointStore,c=e.paramsStore,d=e.signature,p=e.filenameParam,q=e.chunking.minFileSize,h=e.deleteBlob,f=e.onGetBlobName,m=t.getName,g=t.getSize,_=function(e){var t=c.get(e);return t[p]=m(e),t},b={putBlob:new qq.azure.PutBlob({getBlobMetadata:_,log:s}),putBlock:new qq.azure.PutBlock({log:s}),putBlockList:new qq.azure.PutBlockList({getBlobMetadata:_,log:s}),getSasForPutBlobOrBlock:new qq.azure.GetSas({cors:l,customHeaders:d.customHeaders,endpointStore:{get:function(){return d.endpoint}},log:s,restRequestVerb:"PUT"})};qq.extend(this,{uploadChunk:function(e,t){var n=new qq.Promise;return o(e,t).then(function(i){var o=a._createXhr(e,t),l=a._getChunkData(e,t);a._registerProgressHandler(e,t,l.size),a._registerXhr(e,t,o,b.putBlock),b.putBlock.upload(e+"."+t,o,i,t,l.blob).then(function(t){a._getPersistableData(e).blockIdEntries||(a._getPersistableData(e).blockIdEntries=[]),a._getPersistableData(e).blockIdEntries.push(t),s("Put Block call succeeded for "+e),n.success({},o)},function(){s(qq.format("Put Block call failed for ID {} on part {}",e,t),"error"),r(o,n)})},n.failure),n},uploadFile:function(e){var t=new qq.Promise,n=a.getFile(e);return o(e).then(function(i){var o=a._createXhr(e);a._registerProgressHandler(e),b.putBlob.upload(e,o,i,n).then(function(){s("Put Blob call succeeded for "+e),t.success({},o)},function(){s("Put Blob call failed for "+e,"error"),r(o,t)})},t.failure),t}}),qq.extend(this,new qq.XhrUploadHandler({options:qq.extend({namespace:"azure"},e),proxy:qq.extend({getEndpoint:e.endpointStore.get},t)})),qq.override(this,function(e){return{expunge:function(t){var n=a._wasCanceled(t),i=a._getPersistableData(t),o=i&&i.blockIdEntries||[];n&&o.length>0&&h(t),e.expunge(t)},finalizeChunks:function(e){return n(e)},_shouldChunkThisFile:function(t){var n=e._shouldChunkThisFile(t);return n&&g(t)>=q}}})},qq.azure.GetSas=function(e){"use strict";function t(e,t,n){var i=o[e];n?i.failure("Received response code "+t.status,t):t.responseText.length?i.success(t.responseText):i.failure("Empty response.",t),delete o[e]}var n,i={cors:{expected:!1,sendCredentials:!1},customHeaders:{},restRequestVerb:"PUT",endpointStore:null,log:function(e,t){}},o={};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",successfulResponseCodes:{GET:[200]},contentType:null,customHeaders:i.customHeaders,endpointStore:i.endpointStore,cors:i.cors,log:i.log,onComplete:t})),qq.extend(this,{request:function(e,t){var r=new qq.Promise,a=i.restRequestVerb;return i.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.",a,e)),o[e]=r,n.initTransport(e).withParams({bloburi:t,_method:a}).withCacheBuster().send(),r}})},qq.UploadSuccessAjaxRequester=function(e){"use strict";function t(e,t,n){var r,a=i[e],s=t.responseText,l={success:!0},u={success:!1};delete i[e],o.log(qq.format("Received the following response body to an upload success request for id {}: {}",e,s));try{r=qq.parseJson(s),n||r&&(r.error||r.success===!1)?(o.log("Upload success request was rejected by the server.","error"),a.failure(qq.extend(r,u))):(o.log("Upload success was acknowledged by the server."),a.success(qq.extend(r,l)))}catch(t){n?(o.log(qq.format("Your server indicated failure in its upload success request response for id {}!",e),"error"),a.failure(u)):(o.log("Upload success was acknowledged by the server."),a.success(l))}}var n,i=[],o={method:"POST",endpoint:null,maxConnections:3,customHeaders:{},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){}};qq.extend(o,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",method:o.method,endpointStore:{get:function(){return o.endpoint}},paramsStore:o.paramsStore,maxConnections:o.maxConnections,customHeaders:o.customHeaders,log:o.log,onComplete:t,cors:o.cors})),qq.extend(this,{sendSuccessRequest:function(e,t){var r=new qq.Promise;return o.log("Submitting upload success request/notification for "+e),n.initTransport(e).withParams(t).send(),i[e]=r,r}})},qq.azure.DeleteBlob=function(e){"use strict";var t,n="DELETE",i={endpointStore:{},onDelete:function(e){},onDeleteComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[202],e}(),contentType:null,endpointStore:i.endpointStore,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete})),qq.extend(this,{method:n,send:function(e){return i.log("Submitting Delete Blob request for "+e),t.initTransport(e).send()}})},qq.azure.PutBlob=function(e){"use strict";var t,n="PUT",i={getBlobMetadata:function(e){},log:function(e,t){}},o={},r={},a={get:function(e){return o[e]}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[201],e}(),contentType:null,customHeaders:function(e){var t=i.getBlobMetadata(e),n=qq.azure.util.getParamsAsHeaders(t);return n["x-ms-blob-type"]="BlockBlob",n},endpointStore:a,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onComplete:function(e,t,n){var i=r[e];delete o[e],delete r[e],n?i.failure():i.success()}})),qq.extend(this,{method:n,upload:function(e,n,a,s){var l=new qq.Promise;return i.log("Submitting Put Blob request for "+e),r[e]=l,o[e]=a,t.initTransport(e).withPayload(s).withHeaders({"Content-Type":s.type}).send(n),l}})},qq.azure.PutBlock=function(e){"use strict";function t(e){var t=5,n=new Array(t+1).join("0"),i=(n+e).slice(-t);return btoa(i)}var n,i="PUT",o={},r={},a={log:function(e,t){}},s={},l={get:function(e){return s[e]}};qq.extend(a,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),contentType:null,endpointStore:l,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:a.log,onComplete:function(e,t,n){var i=r[e],a=o[e];delete s[e],delete r[e],delete o[e],n?i.failure():i.success(a)}})),qq.extend(this,{method:i,upload:function(e,i,l,u,c){var d=new qq.Promise,p=t(u);return r[e]=d,a.log(qq.format("Submitting Put Block request for {} = part {}",e,u)),s[e]=qq.format("{}&comp=block&blockid={}",l,encodeURIComponent(p)),o[e]={part:u,id:p},n.initTransport(e).withPayload(c).send(i),d}})},qq.azure.PutBlockList=function(e){"use strict";function t(e){var t=document.implementation.createDocument(null,"BlockList",null);return e.sort(function(e,t){return e.part-t.part}),qq.each(e,function(e,n){var i=t.createElement("Latest"),o=t.createTextNode(n.id);i.appendChild(o),qq(t).children()[0].appendChild(i)}),(new XMLSerializer).serializeToString(t)}var n,i="PUT",o={},r={getBlobMetadata:function(e){},log:function(e,t){}},a={},s={get:function(e){return a[e]}};qq.extend(r,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),customHeaders:function(e){var t=r.getBlobMetadata(e);return qq.azure.util.getParamsAsHeaders(t)},contentType:"text/plain",endpointStore:s,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:r.log,onSend:function(){},onComplete:function(e,t,n){var i=o[e];delete a[e],delete o[e],n?i.failure(t):i.success(t)}})),qq.extend(this,{method:i,send:function(e,i,s,l,u){var c,d=new qq.Promise,p=t(s);return o[e]=d,r.log(qq.format("Submitting Put Block List request for {}",e)),a[e]=qq.format("{}&comp=blocklist",i),c=n.initTransport(e).withPayload(p).withHeaders({"x-ms-blob-content-type":l}).send(),u(c),d}})},qq.DragAndDrop=function(e){"use strict";function t(e,t){var n=Array.prototype.slice.call(e);u.callbacks.dropLog("Grabbed "+e.length+" dropped files."),t.dropDisabled(!1),u.callbacks.processingDroppedFilesComplete(n,t.getElement())}function n(e){var t=new qq.Promise;return e.isFile?e.file(function(n){var i=e.name,o=e.fullPath,r=o.indexOf(i);o=o.substr(0,r),"/"===o.charAt(0)&&(o=o.substr(1)),n.qqPath=o,q.push(n),t.success()},function(n){u.callbacks.dropLog("Problem parsing '"+e.fullPath+"'. FileError code "+n.code+".","error"),t.failure()}):e.isDirectory&&i(e).then(function(e){var i=e.length;qq.each(e,function(e,o){n(o).done(function(){i-=1,0===i&&t.success()})}),e.length||t.success()},function(n){u.callbacks.dropLog("Problem parsing '"+e.fullPath+"'. FileError code "+n.code+".","error"),t.failure()}),t}function i(e,t,n,o){var r=o||new qq.Promise,a=t||e.createReader();return a.readEntries(function(t){var o=n?n.concat(t):t;t.length?setTimeout(function(){i(e,a,o,r)},0):r.success(o)},r.failure),r}function o(e,t){var i=[],o=new qq.Promise;return u.callbacks.processingDroppedFiles(),t.dropDisabled(!0),e.files.length>1&&!u.allowMultipleItems?(u.callbacks.processingDroppedFilesComplete([]),u.callbacks.dropError("tooManyFilesError",""),t.dropDisabled(!1),o.failure()):(q=[],qq.isFolderDropSupported(e)?qq.each(e.items,function(e,t){var r=t.webkitGetAsEntry();r&&(r.isFile?q.push(t.getAsFile()):i.push(n(r).done(function(){i.pop(),0===i.length&&o.success()})))}):q=e.files,0===i.length&&o.success()),o}function r(e){var n=new qq.UploadDropZone({HIDE_ZONES_EVENT_NAME:c,element:e,onEnter:function(t){qq(e).addClass(u.classes.dropActive),t.stopPropagation()},onLeaveNotDescendants:function(t){qq(e).removeClass(u.classes.dropActive)},onDrop:function(e){o(e.dataTransfer,n).then(function(){t(q,n)},function(){u.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.","error")})}});return h.addDisposer(function(){n.dispose()}),qq(e).hasAttribute(d)&&qq(e).hide(),p.push(n),n}function a(e){var t;return qq.each(e.dataTransfer.types,function(e,n){if("Files"===n)return t=!0,!1}),t}function s(e){return qq.firefox()?!e.relatedTarget:qq.safari()?e.x<0||e.y<0:0===e.x&&0===e.y}function l(){var e=u.dropZoneElements,t=function(){setTimeout(function(){qq.each(e,function(e,t){qq(t).hasAttribute(d)&&qq(t).hide(),qq(t).removeClass(u.classes.dropActive)})},10)};qq.each(e,function(t,n){var i=r(n);e.length&&qq.supportedFeatures.fileDrop&&h.attach(document,"dragenter",function(t){!i.dropDisabled()&&a(t)&&qq.each(e,function(e,t){t instanceof HTMLElement&&qq(t).hasAttribute(d)&&qq(t).css({display:"block"})})})}),h.attach(document,"dragleave",function(e){s(e)&&t()}),h.attach(qq(document).children()[0],"mouseenter",function(e){t()}),h.attach(document,"drop",function(e){e.preventDefault(),t()}),h.attach(document,c,t)}var u,c="qq-hidezones",d="qq-hide-dropzone",p=[],q=[],h=new qq.DisposeSupport;u={dropZoneElements:[],allowMultipleItems:!0,classes:{dropActive:null},callbacks:new qq.DragAndDrop.callbacks},qq.extend(u,e,!0),l(),qq.extend(this,{setupExtraDropzone:function(e){u.dropZoneElements.push(e),r(e)},removeDropzone:function(e){var t,n=u.dropZoneElements;for(t in n)if(n[t]===e)return n.splice(t,1)},dispose:function(){h.dispose(),qq.each(p,function(e,t){t.dispose()})}})},qq.DragAndDrop.callbacks=function(){"use strict";return{processingDroppedFiles:function(){},processingDroppedFilesComplete:function(e,t){},dropError:function(e,t){qq.log("Drag & drop error code '"+e+" with these specifics: '"+t+"'","error")},dropLog:function(e,t){qq.log(e,t)}}},qq.UploadDropZone=function(e){"use strict";function t(){return qq.safari()||qq.firefox()&&qq.windows()}function n(e){c||(t?d.attach(document,"dragover",function(e){e.preventDefault()}):d.attach(document,"dragover",function(e){e.dataTransfer&&(e.dataTransfer.dropEffect="none",e.preventDefault())}),c=!0)}function i(e){if(!qq.supportedFeatures.fileDrop)return!1;var t,n=e.dataTransfer,i=qq.safari();return t=!(!qq.ie()||!qq.supportedFeatures.fileDrop)||"none"!==n.effectAllowed,n&&t&&(n.files||!i&&n.types.contains&&n.types.contains("Files"))}function o(e){return void 0!==e&&(u=e),u}function r(){function e(){t=document.createEvent("Event"),t.initEvent(s.HIDE_ZONES_EVENT_NAME,!0,!0)}var t;if(window.CustomEvent)try{t=new CustomEvent(s.HIDE_ZONES_EVENT_NAME)}catch(t){e()}else e();document.dispatchEvent(t)}function a(){d.attach(l,"dragover",function(e){if(i(e)){var t=qq.ie()&&qq.supportedFeatures.fileDrop?null:e.dataTransfer.effectAllowed;"move"===t||"linkMove"===t?e.dataTransfer.dropEffect="move":e.dataTransfer.dropEffect="copy",e.stopPropagation(),e.preventDefault()}}),d.attach(l,"dragenter",function(e){if(!o()){if(!i(e))return;s.onEnter(e)}}),d.attach(l,"dragleave",function(e){if(i(e)){s.onLeave(e);var t=document.elementFromPoint(e.clientX,e.clientY);qq(this).contains(t)||s.onLeaveNotDescendants(e)}}),d.attach(l,"drop",function(e){if(!o()){if(!i(e))return;e.preventDefault(),e.stopPropagation(),s.onDrop(e),r()}})}var s,l,u,c,d=new qq.DisposeSupport;s={element:null,onEnter:function(e){},onLeave:function(e){},onLeaveNotDescendants:function(e){},onDrop:function(e){}},qq.extend(s,e),l=s.element,n(),a(),qq.extend(this,{dropDisabled:function(e){return o(e)},dispose:function(){d.dispose()},getElement:function(){return l}})},function(){"use strict";qq.uiPublicApi={addInitialFiles:function(e){this._parent.prototype.addInitialFiles.apply(this,arguments),this._templating.addCacheToDom()},clearStoredFiles:function(){this._parent.prototype.clearStoredFiles.apply(this,arguments),this._templating.clearFiles()},addExtraDropzone:function(e){this._dnd&&this._dnd.setupExtraDropzone(e)},removeExtraDropzone:function(e){if(this._dnd)return this._dnd.removeDropzone(e)},getItemByFileId:function(e){if(!this._templating.isHiddenForever(e))return this._templating.getFileContainer(e)},reset:function(){this._parent.prototype.reset.apply(this,arguments),this._templating.reset(),!this._options.button&&this._templating.getButton()&&(this._defaultButtonId=this._createUploadButton({element:this._templating.getButton(),title:this._options.text.fileInputTitle}).getButtonId()),this._dnd&&(this._dnd.dispose(),this._dnd=this._setupDragAndDrop()),this._totalFilesInBatch=0,this._filesInBatchAddedToUi=0,this._setupClickAndEditEventHandlers()},setName:function(e,t){var n=this._options.formatFileName(t);this._parent.prototype.setName.apply(this,arguments),this._templating.updateFilename(e,n)},pauseUpload:function(e){var t=this._parent.prototype.pauseUpload.apply(this,arguments);return t&&this._templating.uploadPaused(e),t},continueUpload:function(e){var t=this._parent.prototype.continueUpload.apply(this,arguments);return t&&this._templating.uploadContinued(e),t},getId:function(e){return this._templating.getFileId(e)},getDropTarget:function(e){var t=this.getFile(e);return t.qqDropTarget}},qq.uiPrivateApi={_getButton:function(e){var t=this._parent.prototype._getButton.apply(this,arguments);return t||e===this._defaultButtonId&&(t=this._templating.getButton()),t},_removeFileItem:function(e){this._templating.removeFile(e)},_setupClickAndEditEventHandlers:function(){this._fileButtonsClickHandler=qq.FileButtonsClickHandler&&this._bindFileButtonsClickEvent(),this._focusinEventSupported=!qq.firefox(),this._isEditFilenameEnabled()&&(this._filenameClickHandler=this._bindFilenameClickEvent(),this._filenameInputFocusInHandler=this._bindFilenameInputFocusInEvent(),this._filenameInputFocusHandler=this._bindFilenameInputFocusEvent())},_setupDragAndDrop:function(){var e=this,t=this._options.dragAndDrop.extraDropzones,n=this._templating,i=n.getDropZone();return i&&t.push(i),new qq.DragAndDrop({dropZoneElements:t,allowMultipleItems:this._options.multiple,classes:{dropActive:this._options.classes.dropActive},callbacks:{processingDroppedFiles:function(){n.showDropProcessing()},processingDroppedFilesComplete:function(t,i){n.hideDropProcessing(),qq.each(t,function(e,t){t.qqDropTarget=i}),t.length&&e.addFiles(t,null,null)},dropError:function(t,n){e._itemError(t,n)},dropLog:function(t,n){e.log(t,n)}}})},_bindFileButtonsClickEvent:function(){var e=this;return new qq.FileButtonsClickHandler({templating:this._templating,log:function(t,n){e.log(t,n)},onDeleteFile:function(t){e.deleteFile(t)},onCancel:function(t){e.cancel(t)},onRetry:function(t){e.retry(t)},onPause:function(t){e.pauseUpload(t)},onContinue:function(t){e.continueUpload(t)},onGetName:function(t){return e.getName(t)}})},_isEditFilenameEnabled:function(){return this._templating.isEditFilenamePossible()&&!this._options.autoUpload&&qq.FilenameClickHandler&&qq.FilenameInputFocusHandler&&qq.FilenameInputFocusHandler},_filenameEditHandler:function(){var e=this,t=this._templating;return{templating:t,log:function(t,n){e.log(t,n)},onGetUploadStatus:function(t){return e.getUploads({id:t}).status},onGetName:function(t){return e.getName(t)},onSetName:function(t,n){e.setName(t,n)},onEditingStatusChange:function(e,n){var i=qq(t.getEditInput(e)),o=qq(t.getFileContainer(e));n?(i.addClass("qq-editing"),t.hideFilename(e),t.hideEditIcon(e)):(i.removeClass("qq-editing"),t.showFilename(e),t.showEditIcon(e)),o.addClass("qq-temp").removeClass("qq-temp")}}},_onUploadStatusChange:function(e,t,n){this._parent.prototype._onUploadStatusChange.apply(this,arguments),this._isEditFilenameEnabled()&&this._templating.getFileContainer(e)&&n!==qq.status.SUBMITTED&&(this._templating.markFilenameEditable(e),this._templating.hideEditIcon(e)),t===qq.status.UPLOAD_RETRYING&&n===qq.status.UPLOADING?(this._templating.hideRetry(e),this._templating.setStatusText(e),qq(this._templating.getFileContainer(e)).removeClass(this._classes.retrying)):n===qq.status.UPLOAD_FAILED&&this._templating.hidePause(e)},_bindFilenameInputFocusInEvent:function(){var e=qq.extend({},this._filenameEditHandler());return new qq.FilenameInputFocusInHandler(e)},_bindFilenameInputFocusEvent:function(){var e=qq.extend({},this._filenameEditHandler());return new qq.FilenameInputFocusHandler(e)},_bindFilenameClickEvent:function(){var e=qq.extend({},this._filenameEditHandler());return new qq.FilenameClickHandler(e)},_storeForLater:function(e){this._parent.prototype._storeForLater.apply(this,arguments),this._templating.hideSpinner(e)},_onAllComplete:function(e,t){this._parent.prototype._onAllComplete.apply(this,arguments),this._templating.resetTotalProgress()},_onSubmit:function(e,t){var n=this.getFile(e);n&&n.qqPath&&this._options.dragAndDrop.reportDirectoryPaths&&this._paramsStore.addReadOnly(e,{qqpath:n.qqPath}),this._parent.prototype._onSubmit.apply(this,arguments),this._addToList(e,t)},_onSubmitted:function(e){this._isEditFilenameEnabled()&&(this._templating.markFilenameEditable(e),this._templating.showEditIcon(e),this._focusinEventSupported||this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(e)))},_onProgress:function(e,t,n,i){this._parent.prototype._onProgress.apply(this,arguments),this._templating.updateProgress(e,n,i),0===i||100===Math.round(n/i*100)?(this._templating.hideCancel(e),this._templating.hidePause(e),this._templating.hideProgress(e),this._templating.setStatusText(e,this._options.text.waitingForResponse),this._displayFileSize(e)):this._displayFileSize(e,n,i)},_onTotalProgress:function(e,t){this._parent.prototype._onTotalProgress.apply(this,arguments),this._templating.updateTotalProgress(e,t)},_onComplete:function(e,t,n,i){function o(t){s&&(a.setStatusText(e),qq(s).removeClass(l._classes.retrying),a.hideProgress(e),l.getUploads({id:e}).status!==qq.status.UPLOAD_FAILED&&a.hideCancel(e),a.hideSpinner(e),t.success?l._markFileAsSuccessful(e):(qq(s).addClass(l._classes.fail),a.showCancel(e),a.isRetryPossible()&&!l._preventRetries[e]&&(qq(s).addClass(l._classes.retryable),a.showRetry(e)),l._controlFailureTextDisplay(e,t)))}var r=this._parent.prototype._onComplete.apply(this,arguments),a=this._templating,s=a.getFileContainer(e),l=this;return r instanceof qq.Promise?r.done(function(e){o(e)}):o(n),r},_markFileAsSuccessful:function(e){var t=this._templating;this._isDeletePossible()&&t.showDeleteButton(e),qq(t.getFileContainer(e)).addClass(this._classes.success),this._maybeUpdateThumbnail(e)},_onUploadPrep:function(e){this._parent.prototype._onUploadPrep.apply(this,arguments),this._templating.showSpinner(e)},_onUpload:function(e,t){var n=this._parent.prototype._onUpload.apply(this,arguments);return this._templating.showSpinner(e),n},_onUploadChunk:function(e,t){this._parent.prototype._onUploadChunk.apply(this,arguments),t.partIndex>0&&this._handler.isResumable(e)&&this._templating.allowPause(e)},_onCancel:function(e,t){this._parent.prototype._onCancel.apply(this,arguments),this._removeFileItem(e),0===this._getNotFinished()&&this._templating.resetTotalProgress()},_onBeforeAutoRetry:function(e){var t,n,i;this._parent.prototype._onBeforeAutoRetry.apply(this,arguments),this._showCancelLink(e),this._options.retry.showAutoRetryNote&&(t=this._autoRetries[e],n=this._options.retry.maxAutoAttempts,i=this._options.retry.autoRetryNote.replace(/\{retryNum\}/g,t),i=i.replace(/\{maxAuto\}/g,n),this._templating.setStatusText(e,i),qq(this._templating.getFileContainer(e)).addClass(this._classes.retrying))},_onBeforeManualRetry:function(e){return this._parent.prototype._onBeforeManualRetry.apply(this,arguments)?(this._templating.resetProgress(e),qq(this._templating.getFileContainer(e)).removeClass(this._classes.fail),this._templating.setStatusText(e),this._templating.showSpinner(e),this._showCancelLink(e),!0):(qq(this._templating.getFileContainer(e)).addClass(this._classes.retryable),this._templating.showRetry(e),!1)},_onSubmitDelete:function(e){var t=qq.bind(this._onSubmitDeleteSuccess,this);this._parent.prototype._onSubmitDelete.call(this,e,t)},_onSubmitDeleteSuccess:function(e,t,n){this._options.deleteFile.forceConfirm?this._showDeleteConfirm.apply(this,arguments):this._sendDeleteRequest.apply(this,arguments)},_onDeleteComplete:function(e,t,n){this._parent.prototype._onDeleteComplete.apply(this,arguments),this._templating.hideSpinner(e),n?(this._templating.setStatusText(e,this._options.deleteFile.deletingFailedText),this._templating.showDeleteButton(e)):this._removeFileItem(e)},_sendDeleteRequest:function(e,t,n){this._templating.hideDeleteButton(e),this._templating.showSpinner(e),this._templating.setStatusText(e,this._options.deleteFile.deletingStatusText),this._deleteHandler.sendDelete.apply(this,arguments)},_showDeleteConfirm:function(e,t,n){var i,o=this.getName(e),r=this._options.deleteFile.confirmMessage.replace(/\{filename\}/g,o),a=(this.getUuid(e),arguments),s=this;i=this._options.showConfirm(r),qq.isGenericPromise(i)?i.then(function(){s._sendDeleteRequest.apply(s,a)}):i!==!1&&s._sendDeleteRequest.apply(s,a)},_addToList:function(e,t,n){var i,o,r=0,a=this._handler.isProxied(e)&&this._options.scaling.hideScaled;this._options.display.prependFiles&&(this._totalFilesInBatch>1&&this._filesInBatchAddedToUi>0&&(r=this._filesInBatchAddedToUi-1),i={index:r}),n||(this._options.disableCancelForFormUploads&&!qq.supportedFeatures.ajaxUploading&&this._templating.disableCancel(),this._options.multiple||(o=this.getUploads({id:e}),this._handledProxyGroup=this._handledProxyGroup||o.proxyGroupId,o.proxyGroupId===this._handledProxyGroup&&o.proxyGroupId||(this._handler.cancelAll(),this._clearList(),this._handledProxyGroup=null))),n?(this._templating.addFileToCache(e,this._options.formatFileName(t),i,a),this._templating.updateThumbnail(e,this._thumbnailUrls[e],!0,this._options.thumbnails.customResizer)):(this._templating.addFile(e,this._options.formatFileName(t),i,a),this._templating.generatePreview(e,this.getFile(e),this._options.thumbnails.customResizer)),this._filesInBatchAddedToUi+=1,(n||this._options.display.fileSizeOnSubmit&&qq.supportedFeatures.ajaxUploading)&&this._displayFileSize(e);
+},_clearList:function(){this._templating.clearFiles(),this.clearStoredFiles()},_displayFileSize:function(e,t,n){var i=this.getSize(e),o=this._formatSize(i);i>=0&&(void 0!==t&&void 0!==n&&(o=this._formatProgress(t,n)),this._templating.updateSize(e,o))},_formatProgress:function(e,t){function n(e,t){i=i.replace(e,t)}var i=this._options.text.formatProgress;return n("{percent}",Math.round(e/t*100)),n("{total_size}",this._formatSize(t)),i},_controlFailureTextDisplay:function(e,t){var n,i,o;n=this._options.failedUploadTextDisplay.mode,i=this._options.failedUploadTextDisplay.responseProperty,"custom"===n?(o=t[i],o||(o=this._options.text.failUpload),this._templating.setStatusText(e,o),this._options.failedUploadTextDisplay.enableTooltip&&this._showTooltip(e,o)):"default"===n?this._templating.setStatusText(e,this._options.text.failUpload):"none"!==n&&this.log("failedUploadTextDisplay.mode value of '"+n+"' is not valid","warn")},_showTooltip:function(e,t){this._templating.getFileContainer(e).title=t},_showCancelLink:function(e){this._options.disableCancelForFormUploads&&!qq.supportedFeatures.ajaxUploading||this._templating.showCancel(e)},_itemError:function(e,t,n){var i=this._parent.prototype._itemError.apply(this,arguments);this._options.showMessage(i)},_batchError:function(e){this._parent.prototype._batchError.apply(this,arguments),this._options.showMessage(e)},_setupPastePrompt:function(){var e=this;this._options.callbacks.onPasteReceived=function(){var t=e._options.paste.namePromptMessage,n=e._options.paste.defaultName;return e._options.showPrompt(t,n)}},_fileOrBlobRejected:function(e,t){this._totalFilesInBatch-=1,this._parent.prototype._fileOrBlobRejected.apply(this,arguments)},_prepareItemsForUpload:function(e,t,n){this._totalFilesInBatch=e.length,this._filesInBatchAddedToUi=0,this._parent.prototype._prepareItemsForUpload.apply(this,arguments)},_maybeUpdateThumbnail:function(e){var t=this._thumbnailUrls[e],n=this.getUploads({id:e}).status;n===qq.status.DELETED||!t&&!this._options.thumbnails.placeholders.waitUntilResponse&&qq.supportedFeatures.imagePreviews||this._templating.updateThumbnail(e,t,this._options.thumbnails.customResizer)},_addCannedFile:function(e){var t=this._parent.prototype._addCannedFile.apply(this,arguments);return this._addToList(t,this.getName(t),!0),this._templating.hideSpinner(t),this._templating.hideCancel(t),this._markFileAsSuccessful(t),t},_setSize:function(e,t){this._parent.prototype._setSize.apply(this,arguments),this._templating.updateSize(e,this._formatSize(t))},_sessionRequestComplete:function(){this._templating.addCacheToDom(),this._parent.prototype._sessionRequestComplete.apply(this,arguments)}}}(),qq.FineUploader=function(e,t){"use strict";var n=this;this._parent=t?qq[t].FineUploaderBasic:qq.FineUploaderBasic,this._parent.apply(this,arguments),qq.extend(this._options,{element:null,button:null,listElement:null,dragAndDrop:{extraDropzones:[],reportDirectoryPaths:!1},text:{formatProgress:"{percent}% of {total_size}",failUpload:"Upload failed",waitingForResponse:"Processing...",paused:"Paused"},template:"qq-template",classes:{retrying:"qq-upload-retrying",retryable:"qq-upload-retryable",success:"qq-upload-success",fail:"qq-upload-fail",editable:"qq-editable",hide:"qq-hide",dropActive:"qq-upload-drop-area-active"},failedUploadTextDisplay:{mode:"default",responseProperty:"error",enableTooltip:!0},messages:{tooManyFilesError:"You may only drop one file",unsupportedBrowser:"Unrecoverable error - this browser does not permit file uploading of any kind."},retry:{showAutoRetryNote:!0,autoRetryNote:"Retrying {retryNum}/{maxAuto}..."},deleteFile:{forceConfirm:!1,confirmMessage:"Are you sure you want to delete {filename}?",deletingStatusText:"Deleting...",deletingFailedText:"Delete failed"},display:{fileSizeOnSubmit:!1,prependFiles:!1},paste:{promptForName:!1,namePromptMessage:"Please name this image"},thumbnails:{customResizer:null,maxCount:0,placeholders:{waitUntilResponse:!1,notAvailablePath:null,waitingPath:null},timeBetweenThumbs:750},scaling:{hideScaled:!1},showMessage:function(e){return n._templating.hasDialog("alert")?n._templating.showDialog("alert",e):void setTimeout(function(){window.alert(e)},0)},showConfirm:function(e){return n._templating.hasDialog("confirm")?n._templating.showDialog("confirm",e):window.confirm(e)},showPrompt:function(e,t){return n._templating.hasDialog("prompt")?n._templating.showDialog("prompt",e,t):window.prompt(e,t)}},!0),qq.extend(this._options,e,!0),this._templating=new qq.Templating({log:qq.bind(this.log,this),templateIdOrEl:this._options.template,containerEl:this._options.element,fileContainerEl:this._options.listElement,button:this._options.button,imageGenerator:this._imageGenerator,classes:{hide:this._options.classes.hide,editable:this._options.classes.editable},limits:{maxThumbs:this._options.thumbnails.maxCount,timeBetweenThumbs:this._options.thumbnails.timeBetweenThumbs},placeholders:{waitUntilUpdate:this._options.thumbnails.placeholders.waitUntilResponse,thumbnailNotAvailable:this._options.thumbnails.placeholders.notAvailablePath,waitingForThumbnail:this._options.thumbnails.placeholders.waitingPath},text:this._options.text}),this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari()?this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari):!qq.supportedFeatures.uploading||this._options.cors.expected&&!qq.supportedFeatures.uploadCors?this._templating.renderFailure(this._options.messages.unsupportedBrowser):(this._wrapCallbacks(),this._templating.render(),this._classes=this._options.classes,!this._options.button&&this._templating.getButton()&&(this._defaultButtonId=this._createUploadButton({element:this._templating.getButton(),title:this._options.text.fileInputTitle}).getButtonId()),this._setupClickAndEditEventHandlers(),qq.DragAndDrop&&qq.supportedFeatures.fileDrop&&(this._dnd=this._setupDragAndDrop()),this._options.paste.targetElement&&this._options.paste.promptForName&&(qq.PasteSupport?this._setupPastePrompt():this.log("Paste support module not found.","error")),this._totalFilesInBatch=0,this._filesInBatchAddedToUi=0)},qq.extend(qq.FineUploader.prototype,qq.basePublicApi),qq.extend(qq.FineUploader.prototype,qq.basePrivateApi),qq.extend(qq.FineUploader.prototype,qq.uiPublicApi),qq.extend(qq.FineUploader.prototype,qq.uiPrivateApi),qq.Templating=function(e){"use strict";var t,n,i,o,r,a,s,l,u="qq-file-id",c="qq-file-id-",d="qq-max-size",p="qq-server-scale",q="qq-hide-dropzone",h="qq-drop-area-text",f="qq-in-progress",m="qq-hidden-forever",g={content:document.createDocumentFragment(),map:{}},_=!1,b=0,v=!1,S=[],y=-1,w={log:null,limits:{maxThumbs:0,timeBetweenThumbs:750},templateIdOrEl:"qq-template",containerEl:null,fileContainerEl:null,button:null,imageGenerator:null,classes:{hide:"qq-hide",editable:"qq-editable"},placeholders:{waitUntilUpdate:!1,thumbnailNotAvailable:null,waitingForThumbnail:null},text:{paused:"Paused"}},x={button:"qq-upload-button-selector",alertDialog:"qq-alert-dialog-selector",dialogCancelButton:"qq-cancel-button-selector",confirmDialog:"qq-confirm-dialog-selector",dialogMessage:"qq-dialog-message-selector",dialogOkButton:"qq-ok-button-selector",promptDialog:"qq-prompt-dialog-selector",uploader:"qq-uploader-selector",drop:"qq-upload-drop-area-selector",list:"qq-upload-list-selector",progressBarContainer:"qq-progress-bar-container-selector",progressBar:"qq-progress-bar-selector",totalProgressBarContainer:"qq-total-progress-bar-container-selector",totalProgressBar:"qq-total-progress-bar-selector",file:"qq-upload-file-selector",spinner:"qq-upload-spinner-selector",size:"qq-upload-size-selector",cancel:"qq-upload-cancel-selector",pause:"qq-upload-pause-selector",continueButton:"qq-upload-continue-selector",deleteButton:"qq-upload-delete-selector",retry:"qq-upload-retry-selector",statusText:"qq-upload-status-text-selector",editFilenameInput:"qq-edit-filename-selector",editNameIcon:"qq-edit-filename-icon-selector",dropText:"qq-upload-drop-area-text-selector",dropProcessing:"qq-drop-processing-selector",dropProcessingSpinner:"qq-drop-processing-spinner-selector",thumbnail:"qq-thumbnail-selector"},F={},C=new qq.Promise,E=new qq.Promise,P=function(){var e=w.placeholders.thumbnailNotAvailable,n=w.placeholders.waitingForThumbnail,i={maxSize:y,scale:l};s&&(e?w.imageGenerator.generate(e,new Image,i).then(function(e){C.success(e)},function(){C.failure(),t("Problem loading 'not available' placeholder image at "+e,"error")}):C.failure(),n?w.imageGenerator.generate(n,new Image,i).then(function(e){E.success(e)},function(){E.failure(),t("Problem loading 'waiting for thumbnail' placeholder image at "+n,"error")}):E.failure())},I=function(e){var t=new qq.Promise;return E.then(function(n){Q(n,e),e.src?t.success():(e.src=n.src,e.onload=function(){e.onload=null,te(e),t.success()})},function(){W(e),t.success()}),t},D=function(e,n,i){var o=X(e);return t("Generating new thumbnail for "+e),n.qqThumbnailId=e,w.imageGenerator.generate(n,o,i).then(function(){b++,te(o),F[e].success()},function(){F[e].failure(),w.placeholders.waitUntilUpdate||Y(e,o)})},T=function(){if(S.length){v=!0;var e=S.shift();e.update?$(e):K(e)}else v=!1},U=function(e){return V(z(e),x.cancel)},B=function(e){return V(z(e),x.continueButton)},A=function(e){return V(r,x[e+"Dialog"])},k=function(e){return V(z(e),x.deleteButton)},R=function(){return V(r,x.dropProcessing)},N=function(e){return V(z(e),x.editNameIcon)},z=function(e){return g.map[e]||qq(a).getFirstByClass(c+e)},L=function(e){return V(z(e),x.file)},O=function(e){return V(z(e),x.pause)},H=function(e){return null==e?V(r,x.totalProgressBarContainer)||V(r,x.totalProgressBar):V(z(e),x.progressBarContainer)||V(z(e),x.progressBar)},M=function(e){return V(z(e),x.retry)},j=function(e){return V(z(e),x.size)},G=function(e){return V(z(e),x.spinner)},V=function(e,t){return e&&qq(e).getFirstByClass(t)},X=function(e){return s&&V(z(e),x.thumbnail)},W=function(e){e&&qq(e).addClass(w.classes.hide)},Q=function(e,t){var n=e.style.maxWidth,i=e.style.maxHeight;i&&n&&!t.style.maxWidth&&!t.style.maxHeight&&qq(t).css({maxWidth:n,maxHeight:i})},Y=function(e,t){var n=F[e]||(new qq.Promise).failure(),i=new qq.Promise;return C.then(function(e){n.then(function(){i.success()},function(){Q(e,t),t.onload=function(){t.onload=null,i.success()},t.src=e.src,te(t)})}),i},J=function(){var e,o,r,a,u,c,f,m,g,_,b;if(t("Parsing template"),null==w.templateIdOrEl)throw new Error("You MUST specify either a template element or ID!");if(qq.isString(w.templateIdOrEl)){if(e=document.getElementById(w.templateIdOrEl),null===e)throw new Error(qq.format("Cannot find template script at ID '{}'!",w.templateIdOrEl));o=e.innerHTML}else{if(void 0===w.templateIdOrEl.innerHTML)throw new Error("You have specified an invalid value for the template option! It must be an ID or an Element.");o=w.templateIdOrEl.innerHTML}if(o=qq.trimStr(o),a=document.createElement("div"),a.appendChild(qq.toElement(o)),b=qq(a).getFirstByClass(x.uploader),w.button&&(c=qq(a).getFirstByClass(x.button),c&&qq(c).remove()),qq.DragAndDrop&&qq.supportedFeatures.fileDrop||(g=qq(a).getFirstByClass(x.dropProcessing),g&&qq(g).remove()),f=qq(a).getFirstByClass(x.drop),f&&!qq.DragAndDrop&&(t("DnD module unavailable.","info"),qq(f).remove()),qq.supportedFeatures.fileDrop?qq(b).hasAttribute(h)&&f&&(_=qq(f).getFirstByClass(x.dropText),_&&qq(_).remove()):(b.removeAttribute(h),f&&qq(f).hasAttribute(q)&&qq(f).css({display:"none"})),m=qq(a).getFirstByClass(x.thumbnail),s?m&&(y=parseInt(m.getAttribute(d)),y=y>0?y:null,l=qq(m).hasAttribute(p)):m&&qq(m).remove(),s=s&&m,n=qq(a).getByClass(x.editFilenameInput).length>0,i=qq(a).getByClass(x.retry).length>0,r=qq(a).getFirstByClass(x.list),null==r)throw new Error("Could not find the file list container in the template!");return u=r.innerHTML,r.innerHTML="",a.getElementsByTagName("DIALOG").length&&document.createElement("dialog"),t("Template parsing complete"),{template:qq.trimStr(a.innerHTML),fileTemplate:qq.trimStr(u)}},Z=function(e,t,n){var i=n,o=i.firstChild;t>0&&(o=qq(i).children()[t].nextSibling),i.insertBefore(e,o)},K=function(e){var t=e.id,n=e.optFileOrBlob,i=n&&n.qqThumbnailId,o=X(t),r={customResizeFunction:e.customResizeFunction,maxSize:y,orient:!0,scale:!0};qq.supportedFeatures.imagePreviews?o?w.limits.maxThumbs&&w.limits.maxThumbs<=b?(Y(t,o),T()):I(o).done(function(){F[t]=new qq.Promise,F[t].done(function(){setTimeout(T,w.limits.timeBetweenThumbs)}),null!=i?ne(t,i):D(t,n,r)}):T():o&&(I(o),T())},$=function(e){var t=e.id,n=e.thumbnailUrl,i=e.showWaitingImg,o=X(t),r={customResizeFunction:e.customResizeFunction,scale:l,maxSize:y};if(o)if(n){if(!(w.limits.maxThumbs&&w.limits.maxThumbs<=b))return i&&I(o),w.imageGenerator.generate(n,o,r).then(function(){te(o),b++,setTimeout(T,w.limits.timeBetweenThumbs)},function(){Y(t,o),setTimeout(T,w.limits.timeBetweenThumbs)});Y(t,o),T()}else Y(t,o),T()},ee=function(e,t){var n=H(e),i=null==e?x.totalProgressBar:x.progressBar;n&&!qq(n).hasClass(i)&&(n=qq(n).getFirstByClass(i)),n&&(qq(n).css({width:t+"%"}),n.setAttribute("aria-valuenow",t))},te=function(e){e&&qq(e).removeClass(w.classes.hide)},ne=function(e,n){var i=X(e),o=X(n);t(qq.format("ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.",e,n,n)),F[n].then(function(){b++,F[e].success(),t(qq.format("Now using previously generated thumbnail created for ID {} on ID {}.",n,e)),i.src=o.src,te(i)},function(){F[e].failure(),w.placeholders.waitUntilUpdate||Y(e,i)})};qq.extend(w,e),t=w.log,qq.supportedFeatures.imagePreviews||(w.limits.timeBetweenThumbs=0,w.limits.maxThumbs=0),r=w.containerEl,s=void 0!==w.imageGenerator,o=J(),P(),qq.extend(this,{render:function(){t("Rendering template in DOM."),b=0,r.innerHTML=o.template,W(R()),this.hideTotalProgress(),a=w.fileContainerEl||V(r,x.list),t("Template rendering complete")},renderFailure:function(e){var t=qq.toElement(e);r.innerHTML="",r.appendChild(t)},reset:function(){this.render()},clearFiles:function(){a.innerHTML=""},disableCancel:function(){_=!0},addFile:function(e,t,n,i,s){var l,d=qq.toElement(o.fileTemplate),p=V(d,x.file),q=V(r,x.uploader),f=s?g.content:a;s&&(g.map[e]=d),qq(d).addClass(c+e),q.removeAttribute(h),p&&(qq(p).setText(t),p.setAttribute("title",t)),d.setAttribute(u,e),n?Z(d,n.index,f):f.appendChild(d),i?(d.style.display="none",qq(d).addClass(m)):(W(H(e)),W(j(e)),W(k(e)),W(M(e)),W(O(e)),W(B(e)),_&&this.hideCancel(e),l=X(e),l&&!l.src&&E.then(function(e){l.src=e.src,e.style.maxHeight&&e.style.maxWidth&&qq(l).css({maxHeight:e.style.maxHeight,maxWidth:e.style.maxWidth}),te(l)}))},addFileToCache:function(e,t,n,i){this.addFile(e,t,n,i,!0)},addCacheToDom:function(){a.appendChild(g.content),g.content=document.createDocumentFragment(),g.map={}},removeFile:function(e){qq(z(e)).remove()},getFileId:function(e){var t=e;if(t){for(;null==t.getAttribute(u);)t=t.parentNode;return parseInt(t.getAttribute(u))}},getFileList:function(){return a},markFilenameEditable:function(e){var t=L(e);t&&qq(t).addClass(w.classes.editable)},updateFilename:function(e,t){var n=L(e);n&&(qq(n).setText(t),n.setAttribute("title",t))},hideFilename:function(e){W(L(e))},showFilename:function(e){te(L(e))},isFileName:function(e){return qq(e).hasClass(x.file)},getButton:function(){return w.button||V(r,x.button)},hideDropProcessing:function(){W(R())},showDropProcessing:function(){te(R())},getDropZone:function(){return V(r,x.drop)},isEditFilenamePossible:function(){return n},hideRetry:function(e){W(M(e))},isRetryPossible:function(){return i},showRetry:function(e){te(M(e))},getFileContainer:function(e){return z(e)},showEditIcon:function(e){var t=N(e);t&&qq(t).addClass(w.classes.editable)},isHiddenForever:function(e){return qq(z(e)).hasClass(m)},hideEditIcon:function(e){var t=N(e);t&&qq(t).removeClass(w.classes.editable)},isEditIcon:function(e){return qq(e).hasClass(x.editNameIcon,!0)},getEditInput:function(e){return V(z(e),x.editFilenameInput)},isEditInput:function(e){return qq(e).hasClass(x.editFilenameInput,!0)},updateProgress:function(e,t,n){var i,o=H(e);o&&n>0&&(i=Math.round(t/n*100),100===i?W(o):te(o),ee(e,i))},updateTotalProgress:function(e,t){this.updateProgress(null,e,t)},hideProgress:function(e){var t=H(e);t&&W(t)},hideTotalProgress:function(){this.hideProgress()},resetProgress:function(e){ee(e,0),this.hideTotalProgress(e)},resetTotalProgress:function(){this.resetProgress()},showCancel:function(e){if(!_){var t=U(e);t&&qq(t).removeClass(w.classes.hide)}},hideCancel:function(e){W(U(e))},isCancel:function(e){return qq(e).hasClass(x.cancel,!0)},allowPause:function(e){te(O(e)),W(B(e))},uploadPaused:function(e){this.setStatusText(e,w.text.paused),this.allowContinueButton(e),W(G(e))},hidePause:function(e){W(O(e))},isPause:function(e){return qq(e).hasClass(x.pause,!0)},isContinueButton:function(e){return qq(e).hasClass(x.continueButton,!0)},allowContinueButton:function(e){te(B(e)),W(O(e))},uploadContinued:function(e){this.setStatusText(e,""),this.allowPause(e),te(G(e))},showDeleteButton:function(e){te(k(e))},hideDeleteButton:function(e){W(k(e))},isDeleteButton:function(e){return qq(e).hasClass(x.deleteButton,!0)},isRetry:function(e){return qq(e).hasClass(x.retry,!0)},updateSize:function(e,t){var n=j(e);n&&(te(n),qq(n).setText(t))},setStatusText:function(e,t){var n=V(z(e),x.statusText);n&&(null==t?qq(n).clearText():qq(n).setText(t))},hideSpinner:function(e){qq(z(e)).removeClass(f),W(G(e))},showSpinner:function(e){qq(z(e)).addClass(f),te(G(e))},generatePreview:function(e,t,n){this.isHiddenForever(e)||(S.push({id:e,customResizeFunction:n,optFileOrBlob:t}),!v&&T())},updateThumbnail:function(e,t,n,i){this.isHiddenForever(e)||(S.push({customResizeFunction:i,update:!0,id:e,thumbnailUrl:t,showWaitingImg:n}),!v&&T())},hasDialog:function(e){return qq.supportedFeatures.dialogElement&&!!A(e)},showDialog:function(e,t,n){var i=A(e),o=V(i,x.dialogMessage),r=i.getElementsByTagName("INPUT")[0],a=V(i,x.dialogCancelButton),s=V(i,x.dialogOkButton),l=new qq.Promise,u=function(){a.removeEventListener("click",c),s&&s.removeEventListener("click",d),l.failure()},c=function(){a.removeEventListener("click",c),i.close()},d=function(){i.removeEventListener("close",u),s.removeEventListener("click",d),i.close(),l.success(r&&r.value)};return i.addEventListener("close",u),a.addEventListener("click",c),s&&s.addEventListener("click",d),r&&(r.value=n),o.textContent=t,i.showModal(),l}})},qq.UiEventHandler=function(e,t){"use strict";function n(e){i.attach(e,o.eventType,function(e){e=e||window.event;var t=e.target||e.srcElement;o.onHandled(t,e)})}var i=new qq.DisposeSupport,o={eventType:"click",attachTo:null,onHandled:function(e,t){}};qq.extend(this,{addHandler:function(e){n(e)},dispose:function(){i.dispose()}}),qq.extend(t,{getFileIdFromItem:function(e){return e.qqFileId},getDisposeSupport:function(){return i}}),qq.extend(o,e),o.attachTo&&n(o.attachTo)},qq.FileButtonsClickHandler=function(e){"use strict";function t(e,t){qq.each(o,function(n,o){var r,a=n.charAt(0).toUpperCase()+n.slice(1);if(i.templating["is"+a](e))return r=i.templating.getFileId(e),qq.preventDefault(t),i.log(qq.format("Detected valid file button click event on file '{}', ID: {}.",i.onGetName(r),r)),o(r),!1})}var n={},i={templating:null,log:function(e,t){},onDeleteFile:function(e){},onCancel:function(e){},onRetry:function(e){},onPause:function(e){},onContinue:function(e){},onGetName:function(e){}},o={cancel:function(e){i.onCancel(e)},retry:function(e){i.onRetry(e)},deleteButton:function(e){i.onDeleteFile(e)},pause:function(e){i.onPause(e)},continueButton:function(e){i.onContinue(e)}};qq.extend(i,e),i.eventType="click",i.onHandled=t,i.attachTo=i.templating.getFileList(),qq.extend(this,new qq.UiEventHandler(i,n))},qq.FilenameClickHandler=function(e){"use strict";function t(e,t){if(i.templating.isFileName(e)||i.templating.isEditIcon(e)){var o=i.templating.getFileId(e),r=i.onGetUploadStatus(o);r===qq.status.SUBMITTED&&(i.log(qq.format("Detected valid filename click event on file '{}', ID: {}.",i.onGetName(o),o)),qq.preventDefault(t),n.handleFilenameEdit(o,e,!0))}}var n={},i={templating:null,log:function(e,t){},classes:{file:"qq-upload-file",editNameIcon:"qq-edit-filename-icon"},onGetUploadStatus:function(e){},onGetName:function(e){}};qq.extend(i,e),i.eventType="click",i.onHandled=t,qq.extend(this,new qq.FilenameEditHandler(i,n))},qq.FilenameInputFocusInHandler=function(e,t){"use strict";function n(e,n){if(i.templating.isEditInput(e)){var o=i.templating.getFileId(e),r=i.onGetUploadStatus(o);r===qq.status.SUBMITTED&&(i.log(qq.format("Detected valid filename input focus event on file '{}', ID: {}.",i.onGetName(o),o)),t.handleFilenameEdit(o,e))}}var i={templating:null,onGetUploadStatus:function(e){},log:function(e,t){}};t||(t={}),i.eventType="focusin",i.onHandled=n,qq.extend(i,e),qq.extend(this,new qq.FilenameEditHandler(i,t))},qq.FilenameInputFocusHandler=function(e){"use strict";e.eventType="focus",e.attachTo=null,qq.extend(this,new qq.FilenameInputFocusInHandler(e,{}))},qq.FilenameEditHandler=function(e,t){"use strict";function n(e){var t=s.onGetName(e),n=t.lastIndexOf(".");return n>0&&(t=t.substr(0,n)),t}function i(e){var t=s.onGetName(e);return qq.getExtension(t)}function o(e,t){var n,o=e.value;void 0!==o&&qq.trimStr(o).length>0&&(n=i(t),void 0!==n&&(o=o+"."+n),s.onSetName(t,o)),s.onEditingStatusChange(t,!1)}function r(e,n){t.getDisposeSupport().attach(e,"blur",function(){o(e,n)})}function a(e,n){t.getDisposeSupport().attach(e,"keyup",function(t){var i=t.keyCode||t.which;13===i&&o(e,n)})}var s={templating:null,log:function(e,t){},onGetUploadStatus:function(e){},onGetName:function(e){},onSetName:function(e,t){},onEditingStatusChange:function(e,t){}};qq.extend(s,e),s.attachTo=s.templating.getFileList(),qq.extend(this,new qq.UiEventHandler(s,t)),qq.extend(t,{handleFilenameEdit:function(e,t,i){var o=s.templating.getEditInput(e);s.onEditingStatusChange(e,!0),o.value=n(e),i&&o.focus(),r(o,e),a(o,e)}})},function(){"use strict";qq.azure.FineUploader=function(e){var t={failedUploadTextDisplay:{mode:"custom"}};qq.extend(t,e,!0),qq.FineUploader.call(this,t,"azure")},qq.extend(qq.azure.FineUploader.prototype,qq.azure.FineUploaderBasic.prototype),qq.extend(qq.azure.FineUploader.prototype,qq.uiPublicApi),qq.extend(qq.azure.FineUploader.prototype,qq.uiPrivateApi),qq.extend(qq.azure.FineUploader.prototype,{})}()}(window,window);
+//# sourceMappingURL=azure.fine-uploader.min.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.min.js.map b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.min.js.map
new file mode 100644
index 000000000000..1fba7dd0f474
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.fine-uploader.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/azure/util.js","../client/js/non-traditional-common/uploader.basic.api.js","../client/js/azure/uploader.basic.js","../client/js/azure/azure.xhr.upload.handler.js","../client/js/azure/get-sas.js","../client/js/uploadsuccess.ajax.requester.js","../client/js/azure/rest/delete-blob.js","../client/js/azure/rest/put-blob.js","../client/js/azure/rest/put-block.js","../client/js/azure/rest/put-block-list.js","../client/js/dnd.js","../client/js/uploader.api.js","../client/js/uploader.js","../client/js/templating.js","../client/js/ui.handler.events.js","../client/js/ui.handler.click.filebuttons.js","../client/js/ui.handler.click.filename.js","../client/js/ui.handler.focusin.filenameinput.js","../client/js/ui.handler.focus.filenameinput.js","../client/js/ui.handler.edit.filename.js","../client/js/azure/uploader.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","intArray","mimeString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","testSupportsFileInputElement","tempInput","supported","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","createInput","BUTTON_ID_ATTR_NAME","buttonId","options","title","self","setMultiple","folders","acceptFiles","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","disposeSupport","onChange","hoverClass","focusClass","ios8BrowserCrashWorkaround","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","byUuid","getDataByStatus","status","statusResults","statuses","index","statusEnum","statusResultIndexes","byStatus","dataIndex","byProxyGroupId","byBatchId","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","params","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","_options","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","fileOrUrl","promiseToReturn","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","callbacks","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","toUpperCase","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","allowedExtensions","accept","validation","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","namespace","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","replacement","extensionsForMessage","placeholderMatch","messages","names","validationBase","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","requestData","dequeue","nextId","queue","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","mandatedParams","optXhr","url","payload","onSend","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","shouldParamsBeInQueryString","contentType","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","acceptHeader","setRequestHeader","allowXRequestedWithAndCacheControl","responseCode","successfulResponseCodes","prepareToSend","validMethods","DELETE","PATCH","POST","PUT","GET","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","preventRetryResponse","controller","chunkingPossible","concurrentChunkingPossible","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","inProgressIdx","responseToReport","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","expungeFile","detachLoadEvents","isCors","postMessageCallbackTimers","corsMessageReceiver","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","onloadCallbacks","onloadCallback","_parseJsonResponse","_detachLoadEvent","formHandlerInstanceId","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","xhrId","ajaxRequester","_getAjaxRequester","chunkFiles","resumeEnabled","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","getMandatedParams","_method","requester","detectSubsampling","img","ctx","iw","naturalWidth","ih","naturalHeight","width","getContext","drawImage","getImageData","detectVerticalSquash","alpha","ratio","sy","ey","py","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","tmpCtx","sx","dx","d","tmpCanvas","vertSquashRatio","dw","dh","dy","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","opt","imgWidth","imgHeight","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","el","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetProtocol","targetHostname","targetPort","targetAnchor","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","TAG_IDS","vals","tagValHex","tagValLength","idHex","tagsToFindIdx","TAG_INFO","274","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","chr1","chr2","enc1","enc2","enc3","output","chr3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","isImage","registerPasteHandler","detachPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","determineNewEndpoint","formEl","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","_form2Obj","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","azure","util","AZURE_PARAM_PREFIX","_paramNameMatchesAzureParameter","_getPrefixedParamName","getParamsAsHeaders","headerName","parseAzureError","codeTag","messageTag","domParser","DOMParser","responseDoc","parseFromString","errorTag","errorDetails","nonTraditionalBasePublicApi","setUploadSuccessParams","_uploadSuccessParamsStore","setUploadSuccessEndpoint","_uploadSuccessEndpointStore","nonTraditionalBasePrivateApi","submitSuccessRequest","successAjaxRequester","onCompleteArgs","successEndpoint","successCustomHeaders","uploadSuccess","successMethod","uploadSuccessParams","fileParams","onSuccessFromServer","successRequestResult","_failedSuccessRequestCallbacks","onFailureFromServer","UploadSuccessAjaxRequester","_getEndpointSpecificParams","sendSuccessRequest","successRequestCallback","signature","blobProperties","minFileSize","_cannedBlobNames","getBlobName","onGetBlobName","_determineBlobName","deleteBlob","_deleteBlob","blobNameOptionValue","fileExtension","blobNameToUse","blobName","relatedToCancel","deleteBlobSasUri","blobUriStore","deleteFileEndpointStore","getSasSuccess","sasUri","getSasFailure","DeleteBlob","getSas","GetSas","restRequestVerb","combineChunks","getSignedUrl","mimeType","blockIdEntries","putBlockList","determineBlobUrl","containerUrl","getBlobNameSuccess","getBlobNameFailure","getSasId","getSasXhr","determineBlobUrlSuccess","blobUrl","getSasForPutBlobOrBlock","determineBlobUrlFailure","azureError","minFileSizeForChunking","getBlobMetadata","putBlob","PutBlob","putBlock","PutBlock","PutBlockList","blockIdEntry","chunkingData","maybePossible","sasResponseReceived","requestPromises","blobUri","requestPromise","restVerb","bloburi","handleSuccessResponse","parsedResponse","pendingRequests","responseJson","successIndicator","failureIndicator","codes","endpoints","promises","endpointHandler","Content-Type","createBlockId","partNum","digits","zeros","paddedPartNum","btoa","blockId","createRequestBody","doc","implementation","createDocument","latestEl","latestTextEl","createTextNode","XMLSerializer","serializeToString","fileMimeType","registerXhrCallback","blockIdsXml","x-ms-blob-content-type","DragAndDrop","uploadDroppedFiles","uploadDropZone","filesAsArray","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","parseEntryPromise","fullPath","indexOfNameInFullPath","qqPath","droppedFiles","fileError","isDirectory","getFilesInDirectory","entriesLeft","accumEntries","existingPromise","dirReader","createReader","readEntries","newEntries","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","allowMultipleItems","dropError","setupDropzone","dropArea","dropZone","UploadDropZone","HIDE_ZONES_EVENT_NAME","onEnter","dropActive","stopPropagation","onLeaveNotDescendants","onDrop","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","relatedTarget","y","setupDragDrop","dropZones","dropZoneElements","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","targetEl","errorSpecifics","dragoverShouldBeCanceled","disableDropOutside","dropOutsideDisabled","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","isOrSetDropDisabled","isDisabled","preventDrop","triggerHidezonesEvent","triggerUsingOldApi","hideZonesEvent","createEvent","initEvent","CustomEvent","dispatchEvent","attachEvents","effect","elementFromPoint","clientX","clientY","uiPublicApi","_parent","_templating","addCacheToDom","clearFiles","addExtraDropzone","_dnd","removeExtraDropzone","getItemByFileId","isHiddenForever","getFileContainer","_setupDragAndDrop","_totalFilesInBatch","_filesInBatchAddedToUi","_setupClickAndEditEventHandlers","formattedFilename","updateFilename","uploadPaused","continued","uploadContinued","getId","fileContainerOrChildEl","getFileId","getDropTarget","qqDropTarget","uiPrivateApi","_removeFileItem","removeFile","_fileButtonsClickHandler","FileButtonsClickHandler","_bindFileButtonsClickEvent","_focusinEventSupported","_isEditFilenameEnabled","_filenameClickHandler","_bindFilenameClickEvent","_filenameInputFocusInHandler","_bindFilenameInputFocusInEvent","_filenameInputFocusHandler","_bindFilenameInputFocusEvent","dragAndDrop","extraDropzones","templating","defaultDropZone","getDropZone","showDropProcessing","hideDropProcessing","errorData","lvl","onDeleteFile","onRetry","onPause","onContinue","onGetName","isEditFilenamePossible","FilenameClickHandler","FilenameInputFocusHandler","_filenameEditHandler","onGetUploadStatus","onSetName","onEditingStatusChange","isEditing","qqInput","getEditInput","qqFileContainer","hideFilename","hideEditIcon","showFilename","showEditIcon","markFilenameEditable","hideRetry","setStatusText","_classes","retrying","hidePause","FilenameInputFocusInHandler","hideSpinner","resetTotalProgress","reportDirectoryPaths","qqpath","_addToList","addHandler","updateProgress","hideCancel","hideProgress","waitingForResponse","_displayFileSize","completeUpload","_markFileAsSuccessful","fail","showCancel","isRetryPossible","showRetry","_controlFailureTextDisplay","parentRetVal","newResult","showDeleteButton","_maybeUpdateThumbnail","showSpinner","allowPause","retryNumForDisplay","maxAuto","retryNote","_showCancelLink","showAutoRetryNote","autoRetryNote","resetProgress","_onSubmitDeleteSuccess","forceConfirm","_showDeleteConfirm","_sendDeleteRequest","deletingFailedText","hideDeleteButton","deletingStatusText","confirmMessage","deleteRequestArgs","showConfirm","canned","prependData","prependIndex","dontDisplay","hideScaled","prependFiles","disableCancel","_handledProxyGroup","_clearList","addFileToCache","updateThumbnail","thumbnails","generatePreview","fileSizeOnSubmit","loadedSize","sizeForDisplay","_formatProgress","uploadedSize","formatProgress","mode","responseProperty","failureReason","failedUploadTextDisplay","failUpload","enableTooltip","_showTooltip","showMessage","_setupPastePrompt","namePromptMessage","defaultVal","showPrompt","fileStatus","placeholders","waitUntilResponse","FineUploader","listElement","template","editable","tooManyFilesError","unsupportedBrowser","promptForName","maxCount","notAvailablePath","waitingPath","timeBetweenThumbs","hasDialog","showDialog","confirm","defaultValue","prompt","Templating","templateIdOrEl","containerEl","fileContainerEl","maxThumbs","waitUntilUpdate","thumbnailNotAvailable","waitingForThumbnail","renderFailure","isEditElementsExist","isRetryElementExist","templateHtml","showThumbnails","serverScale","FILE_ID_ATTR","FILE_CLASS_PREFIX","THUMBNAIL_MAX_SIZE_ATTR","THUMBNAIL_SERVER_SCALE_ATTR","HIDE_DROPZONE_ATTR","DROPZPONE_TEXT_ATTR","IN_PROGRESS_CLASS","HIDDEN_FOREVER_CLASS","fileBatch","content","createDocumentFragment","map","isCancelDisabled","generatedThumbnails","thumbnailQueueMonitorRunning","thumbGenerationQueue","thumbnailMaxSize","selectorClasses","alertDialog","dialogCancelButton","confirmDialog","dialogMessage","dialogOkButton","promptDialog","uploader","drop","list","progressBarContainer","totalProgressBarContainer","totalProgressBar","spinner","continueButton","deleteButton","statusText","editFilenameInput","editNameIcon","dropText","dropProcessing","dropProcessingSpinner","thumbnail","previewGeneration","cachedThumbnailNotAvailableImg","cachedWaitingForThumbnailImg","cacheThumbnailPlaceholders","notAvailableUrl","waitingUrl","updatedImg","displayWaitingImg","waitingImgPlacement","maybeScalePlaceholderViaCss","show","generateNewPreview","getThumbnail","qqThumbnailId","maybeSetDisplayNotAvailableImg","generateNextQueuedPreview","queuedThumbRequest","update","processUpdateQueuedPreviewRequest","processNewQueuedPreviewRequest","getCancel","getTemplateEl","getContinue","getDialog","getDelete","getDropProcessing","getEditIcon","getPause","getProgress","getRetry","getSpinner","cssClass","previewing","notAvailableImgPlacement","parseAndGetTemplate","scriptEl","scriptHtml","fileListNode","tempTemplateEl","fileListHtml","defaultButton","dropTextEl","uploaderEl","fileTemplate","prependFile","parentEl","beforeEl","optFileOrBlob","relatedThumbnailId","useCachedPreview","showWaitingImg","setProgressBarWidth","percent","bar","progressBarSelector","targetThumbnailId","cachedThumbnailId","targetThumbnail","cachedThumbnail","hideTotalProgress","cantRenderEl","prependInfo","hideForever","batch","thumb","fileEl","fileNameEl","waitingImg","currentNode","getFileList","filenameEl","isFileName","icon","isEditIcon","isEditInput","isCancel","allowContinueButton","isPause","isContinueButton","isDeleteButton","isRetry","textEl","dialog","messageEl","inputEl","cancelBtn","okBtn","closeHandler","cancelClickHandler","okClickHandler","close","showModal","UiEventHandler","s","protectedApi","eventType","srcElement","onHandled","attachTo","getFileIdFromItem","qqFileId","getDisposeSupport","examineEvent","buttonHandlers","buttonType","firstLetterCapButtonType","inheritedInternalApi","handleFilenameEdit","FilenameEditHandler","handleInputFocus","getFilenameSansExtension","filenameSansExt","getOriginalExtension","origName","handleNameUpdate","newFilenameInputEl","origExtension","registerInputBlurHandler","registerInputEnterKeyHandler","keyCode","which","focusInput","focus"],"mappings":"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","file":"azure.fine-uploader.min.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\"\"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n","/*globals qq, document, CustomEvent*/\nqq.DragAndDrop = function(o) {\n \"use strict\";\n\n var options,\n HIDE_ZONES_EVENT_NAME = \"qq-hidezones\",\n HIDE_BEFORE_ENTER_ATTR = \"qq-hide-dropzone\",\n uploadDropZones = [],\n droppedFiles = [],\n disposeSupport = new qq.DisposeSupport();\n\n options = {\n dropZoneElements: [],\n allowMultipleItems: true,\n classes: {\n dropActive: null\n },\n callbacks: new qq.DragAndDrop.callbacks()\n };\n\n qq.extend(options, o, true);\n\n function uploadDroppedFiles(files, uploadDropZone) {\n // We need to convert the `FileList` to an actual `Array` to avoid iteration issues\n var filesAsArray = Array.prototype.slice.call(files);\n\n options.callbacks.dropLog(\"Grabbed \" + files.length + \" dropped files.\");\n uploadDropZone.dropDisabled(false);\n options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());\n }\n\n function traverseFileTree(entry) {\n var parseEntryPromise = new qq.Promise();\n\n if (entry.isFile) {\n entry.file(function(file) {\n var name = entry.name,\n fullPath = entry.fullPath,\n indexOfNameInFullPath = fullPath.indexOf(name);\n\n // remove file name from full path string\n fullPath = fullPath.substr(0, indexOfNameInFullPath);\n\n // remove leading slash in full path string\n if (fullPath.charAt(0) === \"/\") {\n fullPath = fullPath.substr(1);\n }\n\n file.qqPath = fullPath;\n droppedFiles.push(file);\n parseEntryPromise.success();\n },\n function(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n });\n }\n else if (entry.isDirectory) {\n getFilesInDirectory(entry).then(\n function allEntriesRead(entries) {\n var entriesLeft = entries.length;\n\n qq.each(entries, function(idx, entry) {\n traverseFileTree(entry).done(function() {\n entriesLeft -= 1;\n\n if (entriesLeft === 0) {\n parseEntryPromise.success();\n }\n });\n });\n\n if (!entries.length) {\n parseEntryPromise.success();\n }\n },\n\n function readFailure(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n }\n );\n }\n\n return parseEntryPromise;\n }\n\n // Promissory. Guaranteed to read all files in the root of the passed directory.\n function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {\n var promise = existingPromise || new qq.Promise(),\n dirReader = reader || entry.createReader();\n\n dirReader.readEntries(\n function readSuccess(entries) {\n var newEntries = accumEntries ? accumEntries.concat(entries) : entries;\n\n if (entries.length) {\n setTimeout(function() { // prevent stack overflow, however unlikely\n getFilesInDirectory(entry, dirReader, newEntries, promise);\n }, 0);\n }\n else {\n promise.success(newEntries);\n }\n },\n\n promise.failure\n );\n\n return promise;\n }\n\n function handleDataTransfer(dataTransfer, uploadDropZone) {\n var pendingFolderPromises = [],\n handleDataTransferPromise = new qq.Promise();\n\n options.callbacks.processingDroppedFiles();\n uploadDropZone.dropDisabled(true);\n\n if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.firefox()) {\n return !e.relatedTarget;\n }\n\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n e.preventDefault();\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n // dt.types.contains check is for firefox\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains(\"Files\")));\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n};\n","/*globals qq */\n/**\n * Defines the public API for FineUploader mode.\n */\n(function() {\n \"use strict\";\n\n qq.uiPublicApi = {\n addInitialFiles: function(cannedFileList) {\n this._parent.prototype.addInitialFiles.apply(this, arguments);\n this._templating.addCacheToDom();\n },\n\n clearStoredFiles: function() {\n this._parent.prototype.clearStoredFiles.apply(this, arguments);\n this._templating.clearFiles();\n },\n\n addExtraDropzone: function(element) {\n this._dnd && this._dnd.setupExtraDropzone(element);\n },\n\n removeExtraDropzone: function(element) {\n if (this._dnd) {\n return this._dnd.removeDropzone(element);\n }\n },\n\n getItemByFileId: function(id) {\n if (!this._templating.isHiddenForever(id)) {\n return this._templating.getFileContainer(id);\n }\n },\n\n reset: function() {\n this._parent.prototype.reset.apply(this, arguments);\n this._templating.reset();\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n if (this._dnd) {\n this._dnd.dispose();\n this._dnd = this._setupDragAndDrop();\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n\n this._setupClickAndEditEventHandlers();\n },\n\n setName: function(id, newName) {\n var formattedFilename = this._options.formatFileName(newName);\n\n this._parent.prototype.setName.apply(this, arguments);\n this._templating.updateFilename(id, formattedFilename);\n },\n\n pauseUpload: function(id) {\n var paused = this._parent.prototype.pauseUpload.apply(this, arguments);\n\n paused && this._templating.uploadPaused(id);\n return paused;\n },\n\n continueUpload: function(id) {\n var continued = this._parent.prototype.continueUpload.apply(this, arguments);\n\n continued && this._templating.uploadContinued(id);\n return continued;\n },\n\n getId: function(fileContainerOrChildEl) {\n return this._templating.getFileId(fileContainerOrChildEl);\n },\n\n getDropTarget: function(fileId) {\n var file = this.getFile(fileId);\n\n return file.qqDropTarget;\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploader mode.\n */\n qq.uiPrivateApi = {\n _getButton: function(buttonId) {\n var button = this._parent.prototype._getButton.apply(this, arguments);\n\n if (!button) {\n if (buttonId === this._defaultButtonId) {\n button = this._templating.getButton();\n }\n }\n\n return button;\n },\n\n _removeFileItem: function(fileId) {\n this._templating.removeFile(fileId);\n },\n\n _setupClickAndEditEventHandlers: function() {\n this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();\n\n // A better approach would be to check specifically for focusin event support by querying the DOM API,\n // but the DOMFocusIn event is not exposed as a property, so we have to resort to UA string sniffing.\n this._focusinEventSupported = !qq.firefox();\n\n if (this._isEditFilenameEnabled())\n {\n this._filenameClickHandler = this._bindFilenameClickEvent();\n this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();\n this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();\n }\n },\n\n _setupDragAndDrop: function() {\n var self = this,\n dropZoneElements = this._options.dragAndDrop.extraDropzones,\n templating = this._templating,\n defaultDropZone = templating.getDropZone();\n\n defaultDropZone && dropZoneElements.push(defaultDropZone);\n\n return new qq.DragAndDrop({\n dropZoneElements: dropZoneElements,\n allowMultipleItems: this._options.multiple,\n classes: {\n dropActive: this._options.classes.dropActive\n },\n callbacks: {\n processingDroppedFiles: function() {\n templating.showDropProcessing();\n },\n processingDroppedFilesComplete: function(files, targetEl) {\n templating.hideDropProcessing();\n\n qq.each(files, function(idx, file) {\n file.qqDropTarget = targetEl;\n });\n\n if (files.length) {\n self.addFiles(files, null, null);\n }\n },\n dropError: function(code, errorData) {\n self._itemError(code, errorData);\n },\n dropLog: function(message, level) {\n self.log(message, level);\n }\n }\n });\n },\n\n _bindFileButtonsClickEvent: function() {\n var self = this;\n\n return new qq.FileButtonsClickHandler({\n templating: this._templating,\n\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n\n onDeleteFile: function(fileId) {\n self.deleteFile(fileId);\n },\n\n onCancel: function(fileId) {\n self.cancel(fileId);\n },\n\n onRetry: function(fileId) {\n self.retry(fileId);\n },\n\n onPause: function(fileId) {\n self.pauseUpload(fileId);\n },\n\n onContinue: function(fileId) {\n self.continueUpload(fileId);\n },\n\n onGetName: function(fileId) {\n return self.getName(fileId);\n }\n });\n },\n\n _isEditFilenameEnabled: function() {\n /*jshint -W014 */\n return this._templating.isEditFilenamePossible()\n && !this._options.autoUpload\n && qq.FilenameClickHandler\n && qq.FilenameInputFocusHandler\n && qq.FilenameInputFocusHandler;\n },\n\n _filenameEditHandler: function() {\n var self = this,\n templating = this._templating;\n\n return {\n templating: templating,\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n onGetUploadStatus: function(fileId) {\n return self.getUploads({id: fileId}).status;\n },\n onGetName: function(fileId) {\n return self.getName(fileId);\n },\n onSetName: function(id, newName) {\n self.setName(id, newName);\n },\n onEditingStatusChange: function(id, isEditing) {\n var qqInput = qq(templating.getEditInput(id)),\n qqFileContainer = qq(templating.getFileContainer(id));\n\n if (isEditing) {\n qqInput.addClass(\"qq-editing\");\n templating.hideFilename(id);\n templating.hideEditIcon(id);\n }\n else {\n qqInput.removeClass(\"qq-editing\");\n templating.showFilename(id);\n templating.showEditIcon(id);\n }\n\n // Force IE8 and older to repaint\n qqFileContainer.addClass(\"qq-temp\").removeClass(\"qq-temp\");\n }\n };\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n this._parent.prototype._onUploadStatusChange.apply(this, arguments);\n\n if (this._isEditFilenameEnabled()) {\n // Status for a file exists before it has been added to the DOM, so we must be careful here.\n if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {\n this._templating.markFilenameEditable(id);\n this._templating.hideEditIcon(id);\n }\n }\n\n if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {\n this._templating.hideRetry(id);\n this._templating.setStatusText(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);\n }\n else if (newStatus === qq.status.UPLOAD_FAILED) {\n this._templating.hidePause(id);\n }\n },\n\n _bindFilenameInputFocusInEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusInHandler(spec);\n },\n\n _bindFilenameInputFocusEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusHandler(spec);\n },\n\n _bindFilenameClickEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameClickHandler(spec);\n },\n\n _storeForLater: function(id) {\n this._parent.prototype._storeForLater.apply(this, arguments);\n this._templating.hideSpinner(id);\n },\n\n _onAllComplete: function(successful, failed) {\n this._parent.prototype._onAllComplete.apply(this, arguments);\n this._templating.resetTotalProgress();\n },\n\n _onSubmit: function(id, name) {\n var file = this.getFile(id);\n\n if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {\n this._paramsStore.addReadOnly(id, {\n qqpath: file.qqPath\n });\n }\n\n this._parent.prototype._onSubmit.apply(this, arguments);\n this._addToList(id, name);\n },\n\n // The file item has been added to the DOM.\n _onSubmitted: function(id) {\n // If the edit filename feature is enabled, mark the filename element as \"editable\" and the associated edit icon\n if (this._isEditFilenameEnabled()) {\n this._templating.markFilenameEditable(id);\n this._templating.showEditIcon(id);\n\n // If the focusin event is not supported, we must add a focus handler to the newly create edit filename text input\n if (!this._focusinEventSupported) {\n this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));\n }\n }\n },\n\n // Update the progress bar & percentage as the file is uploaded\n _onProgress: function(id, name, loaded, total) {\n this._parent.prototype._onProgress.apply(this, arguments);\n\n this._templating.updateProgress(id, loaded, total);\n\n if (total === 0 || Math.round(loaded / total * 100) === 100) {\n this._templating.hideCancel(id);\n this._templating.hidePause(id);\n this._templating.hideProgress(id);\n this._templating.setStatusText(id, this._options.text.waitingForResponse);\n\n // If ~last byte was sent, display total file size\n this._displayFileSize(id);\n }\n else {\n // If still uploading, display percentage - total size is actually the total request(s) size\n this._displayFileSize(id, loaded, total);\n }\n },\n\n _onTotalProgress: function(loaded, total) {\n this._parent.prototype._onTotalProgress.apply(this, arguments);\n this._templating.updateTotalProgress(loaded, total);\n },\n\n _onComplete: function(id, name, result, xhr) {\n var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments),\n templating = this._templating,\n fileContainer = templating.getFileContainer(id),\n self = this;\n\n function completeUpload(result) {\n // If this file is not represented in the templating module, perhaps it was hidden intentionally.\n // If so, don't perform any UI-related tasks related to this file.\n if (!fileContainer) {\n return;\n }\n\n templating.setStatusText(id);\n\n qq(fileContainer).removeClass(self._classes.retrying);\n templating.hideProgress(id);\n\n if (self.getUploads({id: id}).status !== qq.status.UPLOAD_FAILED) {\n templating.hideCancel(id);\n }\n templating.hideSpinner(id);\n\n if (result.success) {\n self._markFileAsSuccessful(id);\n }\n else {\n qq(fileContainer).addClass(self._classes.fail);\n templating.showCancel(id);\n\n if (templating.isRetryPossible() && !self._preventRetries[id]) {\n qq(fileContainer).addClass(self._classes.retryable);\n templating.showRetry(id);\n }\n self._controlFailureTextDisplay(id, result);\n }\n }\n\n // The parent may need to perform some async operation before we can accurately determine the status of the upload.\n if (parentRetVal instanceof qq.Promise) {\n parentRetVal.done(function(newResult) {\n completeUpload(newResult);\n });\n\n }\n else {\n completeUpload(result);\n }\n\n return parentRetVal;\n },\n\n _markFileAsSuccessful: function(id) {\n var templating = this._templating;\n\n if (this._isDeletePossible()) {\n templating.showDeleteButton(id);\n }\n\n qq(templating.getFileContainer(id)).addClass(this._classes.success);\n\n this._maybeUpdateThumbnail(id);\n },\n\n _onUploadPrep: function(id) {\n this._parent.prototype._onUploadPrep.apply(this, arguments);\n this._templating.showSpinner(id);\n },\n\n _onUpload: function(id, name) {\n var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);\n\n this._templating.showSpinner(id);\n\n return parentRetVal;\n },\n\n _onUploadChunk: function(id, chunkData) {\n this._parent.prototype._onUploadChunk.apply(this, arguments);\n\n // Only display the pause button if we have finished uploading at least one chunk\n // & this file can be resumed\n if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {\n this._templating.allowPause(id);\n }\n },\n\n _onCancel: function(id, name) {\n this._parent.prototype._onCancel.apply(this, arguments);\n this._removeFileItem(id);\n\n if (this._getNotFinished() === 0) {\n this._templating.resetTotalProgress();\n }\n },\n\n _onBeforeAutoRetry: function(id) {\n var retryNumForDisplay, maxAuto, retryNote;\n\n this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);\n\n this._showCancelLink(id);\n\n if (this._options.retry.showAutoRetryNote) {\n retryNumForDisplay = this._autoRetries[id];\n maxAuto = this._options.retry.maxAutoAttempts;\n\n retryNote = this._options.retry.autoRetryNote.replace(/\\{retryNum\\}/g, retryNumForDisplay);\n retryNote = retryNote.replace(/\\{maxAuto\\}/g, maxAuto);\n\n this._templating.setStatusText(id, retryNote);\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);\n }\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {\n this._templating.resetProgress(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);\n this._templating.setStatusText(id);\n this._templating.showSpinner(id);\n this._showCancelLink(id);\n return true;\n }\n else {\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);\n this._templating.showRetry(id);\n return false;\n }\n },\n\n _onSubmitDelete: function(id) {\n var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);\n\n this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);\n },\n\n _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {\n if (this._options.deleteFile.forceConfirm) {\n this._showDeleteConfirm.apply(this, arguments);\n }\n else {\n this._sendDeleteRequest.apply(this, arguments);\n }\n },\n\n _onDeleteComplete: function(id, xhr, isError) {\n this._parent.prototype._onDeleteComplete.apply(this, arguments);\n\n this._templating.hideSpinner(id);\n\n if (isError) {\n this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);\n this._templating.showDeleteButton(id);\n }\n else {\n this._removeFileItem(id);\n }\n },\n\n _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {\n this._templating.hideDeleteButton(id);\n this._templating.showSpinner(id);\n this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);\n this._deleteHandler.sendDelete.apply(this, arguments);\n },\n\n _showDeleteConfirm: function(id, uuid, mandatedParams) {\n /*jshint -W004 */\n var fileName = this.getName(id),\n confirmMessage = this._options.deleteFile.confirmMessage.replace(/\\{filename\\}/g, fileName),\n uuid = this.getUuid(id),\n deleteRequestArgs = arguments,\n self = this,\n retVal;\n\n retVal = this._options.showConfirm(confirmMessage);\n\n if (qq.isGenericPromise(retVal)) {\n retVal.then(function() {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n });\n }\n else if (retVal !== false) {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n }\n },\n\n _addToList: function(id, name, canned) {\n var prependData,\n prependIndex = 0,\n dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled,\n record;\n\n if (this._options.display.prependFiles) {\n if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {\n prependIndex = this._filesInBatchAddedToUi - 1;\n }\n\n prependData = {\n index: prependIndex\n };\n }\n\n if (!canned) {\n if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {\n this._templating.disableCancel();\n }\n\n // Cancel all existing (previous) files and clear the list if this file is not part of\n // a scaled file group that has already been accepted, or if this file is not part of\n // a scaled file group at all.\n if (!this._options.multiple) {\n record = this.getUploads({id: id});\n\n this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;\n\n if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {\n this._handler.cancelAll();\n this._clearList();\n this._handledProxyGroup = null;\n }\n }\n }\n\n if (canned) {\n this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);\n }\n else {\n this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);\n }\n\n this._filesInBatchAddedToUi += 1;\n\n if (canned ||\n (this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading)) {\n\n this._displayFileSize(id);\n }\n },\n\n _clearList: function() {\n this._templating.clearFiles();\n this.clearStoredFiles();\n },\n\n _displayFileSize: function(id, loadedSize, totalSize) {\n var size = this.getSize(id),\n sizeForDisplay = this._formatSize(size);\n\n if (size >= 0) {\n if (loadedSize !== undefined && totalSize !== undefined) {\n sizeForDisplay = this._formatProgress(loadedSize, totalSize);\n }\n\n this._templating.updateSize(id, sizeForDisplay);\n }\n },\n\n _formatProgress: function(uploadedSize, totalSize) {\n var message = this._options.text.formatProgress;\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n r(\"{percent}\", Math.round(uploadedSize / totalSize * 100));\n r(\"{total_size}\", this._formatSize(totalSize));\n return message;\n },\n\n _controlFailureTextDisplay: function(id, response) {\n var mode, responseProperty, failureReason;\n\n mode = this._options.failedUploadTextDisplay.mode;\n responseProperty = this._options.failedUploadTextDisplay.responseProperty;\n\n if (mode === \"custom\") {\n failureReason = response[responseProperty];\n if (!failureReason) {\n failureReason = this._options.text.failUpload;\n }\n\n this._templating.setStatusText(id, failureReason);\n\n if (this._options.failedUploadTextDisplay.enableTooltip) {\n this._showTooltip(id, failureReason);\n }\n }\n else if (mode === \"default\") {\n this._templating.setStatusText(id, this._options.text.failUpload);\n }\n else if (mode !== \"none\") {\n this.log(\"failedUploadTextDisplay.mode value of '\" + mode + \"' is not valid\", \"warn\");\n }\n },\n\n _showTooltip: function(id, text) {\n this._templating.getFileContainer(id).title = text;\n },\n\n _showCancelLink: function(id) {\n if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {\n this._templating.showCancel(id);\n }\n },\n\n _itemError: function(code, name, item) {\n var message = this._parent.prototype._itemError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _batchError: function(message) {\n this._parent.prototype._batchError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _setupPastePrompt: function() {\n var self = this;\n\n this._options.callbacks.onPasteReceived = function() {\n var message = self._options.paste.namePromptMessage,\n defaultVal = self._options.paste.defaultName;\n\n return self._options.showPrompt(message, defaultVal);\n };\n },\n\n _fileOrBlobRejected: function(id, name) {\n this._totalFilesInBatch -= 1;\n this._parent.prototype._fileOrBlobRejected.apply(this, arguments);\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n this._totalFilesInBatch = items.length;\n this._filesInBatchAddedToUi = 0;\n this._parent.prototype._prepareItemsForUpload.apply(this, arguments);\n },\n\n _maybeUpdateThumbnail: function(fileId) {\n var thumbnailUrl = this._thumbnailUrls[fileId],\n fileStatus = this.getUploads({id: fileId}).status;\n\n if (fileStatus !== qq.status.DELETED &&\n (thumbnailUrl ||\n this._options.thumbnails.placeholders.waitUntilResponse ||\n !qq.supportedFeatures.imagePreviews)) {\n\n // This will replace the \"waiting\" placeholder with a \"preview not available\" placeholder\n // if called with a null thumbnailUrl.\n this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id = this._parent.prototype._addCannedFile.apply(this, arguments);\n\n this._addToList(id, this.getName(id), true);\n this._templating.hideSpinner(id);\n this._templating.hideCancel(id);\n this._markFileAsSuccessful(id);\n\n return id;\n },\n\n _setSize: function(id, newSize) {\n this._parent.prototype._setSize.apply(this, arguments);\n\n this._templating.updateSize(id, this._formatSize(newSize));\n },\n\n _sessionRequestComplete: function() {\n this._templating.addCacheToDom();\n this._parent.prototype._sessionRequestComplete.apply(this, arguments);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploader mode, which is a default UI w/ drag & drop uploading.\n */\nqq.FineUploader = function(o, namespace) {\n \"use strict\";\n\n var self = this;\n\n // By default this should inherit instance data from FineUploaderBasic, but this can be overridden\n // if the (internal) caller defines a different parent. The parent is also used by\n // the private and public API functions that need to delegate to a parent function.\n this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;\n this._parent.apply(this, arguments);\n\n // Options provided by FineUploader mode\n qq.extend(this._options, {\n element: null,\n\n button: null,\n\n listElement: null,\n\n dragAndDrop: {\n extraDropzones: [],\n reportDirectoryPaths: false\n },\n\n text: {\n formatProgress: \"{percent}% of {total_size}\",\n failUpload: \"Upload failed\",\n waitingForResponse: \"Processing...\",\n paused: \"Paused\"\n },\n\n template: \"qq-template\",\n\n classes: {\n retrying: \"qq-upload-retrying\",\n retryable: \"qq-upload-retryable\",\n success: \"qq-upload-success\",\n fail: \"qq-upload-fail\",\n editable: \"qq-editable\",\n hide: \"qq-hide\",\n dropActive: \"qq-upload-drop-area-active\"\n },\n\n failedUploadTextDisplay: {\n mode: \"default\", //default, custom, or none\n responseProperty: \"error\",\n enableTooltip: true\n },\n\n messages: {\n tooManyFilesError: \"You may only drop one file\",\n unsupportedBrowser: \"Unrecoverable error - this browser does not permit file uploading of any kind.\"\n },\n\n retry: {\n showAutoRetryNote: true,\n autoRetryNote: \"Retrying {retryNum}/{maxAuto}...\"\n },\n\n deleteFile: {\n forceConfirm: false,\n confirmMessage: \"Are you sure you want to delete {filename}?\",\n deletingStatusText: \"Deleting...\",\n deletingFailedText: \"Delete failed\"\n\n },\n\n display: {\n fileSizeOnSubmit: false,\n prependFiles: false\n },\n\n paste: {\n promptForName: false,\n namePromptMessage: \"Please name this image\"\n },\n\n thumbnails: {\n customResizer: null,\n maxCount: 0,\n placeholders: {\n waitUntilResponse: false,\n notAvailablePath: null,\n waitingPath: null\n },\n timeBetweenThumbs: 750\n },\n\n scaling: {\n hideScaled: false\n },\n\n showMessage: function(message) {\n if (self._templating.hasDialog(\"alert\")) {\n return self._templating.showDialog(\"alert\", message);\n }\n else {\n setTimeout(function() {\n window.alert(message);\n }, 0);\n }\n },\n\n showConfirm: function(message) {\n if (self._templating.hasDialog(\"confirm\")) {\n return self._templating.showDialog(\"confirm\", message);\n }\n else {\n return window.confirm(message);\n }\n },\n\n showPrompt: function(message, defaultValue) {\n if (self._templating.hasDialog(\"prompt\")) {\n return self._templating.showDialog(\"prompt\", message, defaultValue);\n }\n else {\n return window.prompt(message, defaultValue);\n }\n }\n }, true);\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._templating = new qq.Templating({\n log: qq.bind(this.log, this),\n templateIdOrEl: this._options.template,\n containerEl: this._options.element,\n fileContainerEl: this._options.listElement,\n button: this._options.button,\n imageGenerator: this._imageGenerator,\n classes: {\n hide: this._options.classes.hide,\n editable: this._options.classes.editable\n },\n limits: {\n maxThumbs: this._options.thumbnails.maxCount,\n timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs\n },\n placeholders: {\n waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,\n thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,\n waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath\n },\n text: this._options.text\n });\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);\n }\n else if (!qq.supportedFeatures.uploading || (this._options.cors.expected && !qq.supportedFeatures.uploadCors)) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowser);\n }\n else {\n this._wrapCallbacks();\n\n this._templating.render();\n\n this._classes = this._options.classes;\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._setupClickAndEditEventHandlers();\n\n if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {\n this._dnd = this._setupDragAndDrop();\n }\n\n if (this._options.paste.targetElement && this._options.paste.promptForName) {\n if (qq.PasteSupport) {\n this._setupPastePrompt();\n }\n else {\n this.log(\"Paste support module not found.\", \"error\");\n }\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n }\n};\n\n// Inherit the base public & private API methods\nqq.extend(qq.FineUploader.prototype, qq.basePublicApi);\nqq.extend(qq.FineUploader.prototype, qq.basePrivateApi);\n\n// Add the FineUploader/default UI public & private UI methods, which may override some base methods.\nqq.extend(qq.FineUploader.prototype, qq.uiPublicApi);\nqq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);\n","/* globals qq */\n/* jshint -W065 */\n/**\n * Module responsible for rendering all Fine Uploader UI templates. This module also asserts at least\n * a limited amount of control over the template elements after they are added to the DOM.\n * Wherever possible, this module asserts total control over template elements present in the DOM.\n *\n * @param spec Specification object used to control various templating behaviors\n * @constructor\n */\nqq.Templating = function(spec) {\n \"use strict\";\n\n var FILE_ID_ATTR = \"qq-file-id\",\n FILE_CLASS_PREFIX = \"qq-file-id-\",\n THUMBNAIL_MAX_SIZE_ATTR = \"qq-max-size\",\n THUMBNAIL_SERVER_SCALE_ATTR = \"qq-server-scale\",\n // This variable is duplicated in the DnD module since it can function as a standalone as well\n HIDE_DROPZONE_ATTR = \"qq-hide-dropzone\",\n DROPZPONE_TEXT_ATTR = \"qq-drop-area-text\",\n IN_PROGRESS_CLASS = \"qq-in-progress\",\n HIDDEN_FOREVER_CLASS = \"qq-hidden-forever\",\n fileBatch = {\n content: document.createDocumentFragment(),\n map: {}\n },\n isCancelDisabled = false,\n generatedThumbnails = 0,\n thumbnailQueueMonitorRunning = false,\n thumbGenerationQueue = [],\n thumbnailMaxSize = -1,\n options = {\n log: null,\n limits: {\n maxThumbs: 0,\n timeBetweenThumbs: 750\n },\n templateIdOrEl: \"qq-template\",\n containerEl: null,\n fileContainerEl: null,\n button: null,\n imageGenerator: null,\n classes: {\n hide: \"qq-hide\",\n editable: \"qq-editable\"\n },\n placeholders: {\n waitUntilUpdate: false,\n thumbnailNotAvailable: null,\n waitingForThumbnail: null\n },\n text: {\n paused: \"Paused\"\n }\n },\n selectorClasses = {\n button: \"qq-upload-button-selector\",\n alertDialog: \"qq-alert-dialog-selector\",\n dialogCancelButton: \"qq-cancel-button-selector\",\n confirmDialog: \"qq-confirm-dialog-selector\",\n dialogMessage: \"qq-dialog-message-selector\",\n dialogOkButton: \"qq-ok-button-selector\",\n promptDialog: \"qq-prompt-dialog-selector\",\n uploader: \"qq-uploader-selector\",\n drop: \"qq-upload-drop-area-selector\",\n list: \"qq-upload-list-selector\",\n progressBarContainer: \"qq-progress-bar-container-selector\",\n progressBar: \"qq-progress-bar-selector\",\n totalProgressBarContainer: \"qq-total-progress-bar-container-selector\",\n totalProgressBar: \"qq-total-progress-bar-selector\",\n file: \"qq-upload-file-selector\",\n spinner: \"qq-upload-spinner-selector\",\n size: \"qq-upload-size-selector\",\n cancel: \"qq-upload-cancel-selector\",\n pause: \"qq-upload-pause-selector\",\n continueButton: \"qq-upload-continue-selector\",\n deleteButton: \"qq-upload-delete-selector\",\n retry: \"qq-upload-retry-selector\",\n statusText: \"qq-upload-status-text-selector\",\n editFilenameInput: \"qq-edit-filename-selector\",\n editNameIcon: \"qq-edit-filename-icon-selector\",\n dropText: \"qq-upload-drop-area-text-selector\",\n dropProcessing: \"qq-drop-processing-selector\",\n dropProcessingSpinner: \"qq-drop-processing-spinner-selector\",\n thumbnail: \"qq-thumbnail-selector\"\n },\n previewGeneration = {},\n cachedThumbnailNotAvailableImg = new qq.Promise(),\n cachedWaitingForThumbnailImg = new qq.Promise(),\n log,\n isEditElementsExist,\n isRetryElementExist,\n templateHtml,\n container,\n fileList,\n showThumbnails,\n serverScale,\n\n // During initialization of the templating module we should cache any\n // placeholder images so we can quickly swap them into the file list on demand.\n // Any placeholder images that cannot be loaded/found are simply ignored.\n cacheThumbnailPlaceholders = function() {\n var notAvailableUrl = options.placeholders.thumbnailNotAvailable,\n waitingUrl = options.placeholders.waitingForThumbnail,\n spec = {\n maxSize: thumbnailMaxSize,\n scale: serverScale\n };\n\n if (showThumbnails) {\n if (notAvailableUrl) {\n options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedThumbnailNotAvailableImg.success(updatedImg);\n },\n function() {\n cachedThumbnailNotAvailableImg.failure();\n log(\"Problem loading 'not available' placeholder image at \" + notAvailableUrl, \"error\");\n }\n );\n }\n else {\n cachedThumbnailNotAvailableImg.failure();\n }\n\n if (waitingUrl) {\n options.imageGenerator.generate(waitingUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedWaitingForThumbnailImg.success(updatedImg);\n },\n function() {\n cachedWaitingForThumbnailImg.failure();\n log(\"Problem loading 'waiting for thumbnail' placeholder image at \" + waitingUrl, \"error\");\n }\n );\n }\n else {\n cachedWaitingForThumbnailImg.failure();\n }\n }\n },\n\n // Displays a \"waiting for thumbnail\" type placeholder image\n // iff we were able to load it during initialization of the templating module.\n displayWaitingImg = function(thumbnail) {\n var waitingImgPlacement = new qq.Promise();\n\n cachedWaitingForThumbnailImg.then(function(img) {\n maybeScalePlaceholderViaCss(img, thumbnail);\n /* jshint eqnull:true */\n if (!thumbnail.src) {\n thumbnail.src = img.src;\n thumbnail.onload = function() {\n thumbnail.onload = null;\n show(thumbnail);\n waitingImgPlacement.success();\n };\n }\n else {\n waitingImgPlacement.success();\n }\n }, function() {\n // In some browsers (such as IE9 and older) an img w/out a src attribute\n // are displayed as \"broken\" images, so we should just hide the img tag\n // if we aren't going to display the \"waiting\" placeholder.\n hide(thumbnail);\n waitingImgPlacement.success();\n });\n\n return waitingImgPlacement;\n },\n\n generateNewPreview = function(id, blob, spec) {\n var thumbnail = getThumbnail(id);\n\n log(\"Generating new thumbnail for \" + id);\n blob.qqThumbnailId = id;\n\n return options.imageGenerator.generate(blob, thumbnail, spec).then(\n function() {\n generatedThumbnails++;\n show(thumbnail);\n previewGeneration[id].success();\n },\n function() {\n previewGeneration[id].failure();\n\n // Display the \"not available\" placeholder img only if we are\n // not expecting a thumbnail at a later point, such as in a server response.\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n }\n });\n },\n\n generateNextQueuedPreview = function() {\n if (thumbGenerationQueue.length) {\n thumbnailQueueMonitorRunning = true;\n\n var queuedThumbRequest = thumbGenerationQueue.shift();\n\n if (queuedThumbRequest.update) {\n processUpdateQueuedPreviewRequest(queuedThumbRequest);\n }\n else {\n processNewQueuedPreviewRequest(queuedThumbRequest);\n }\n }\n else {\n thumbnailQueueMonitorRunning = false;\n }\n },\n\n getCancel = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.cancel);\n },\n\n getContinue = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.continueButton);\n },\n\n getDialog = function(type) {\n return getTemplateEl(container, selectorClasses[type + \"Dialog\"]);\n },\n\n getDelete = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.deleteButton);\n },\n\n getDropProcessing = function() {\n return getTemplateEl(container, selectorClasses.dropProcessing);\n },\n\n getEditIcon = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editNameIcon);\n },\n\n getFile = function(id) {\n return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);\n },\n\n getFilename = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.file);\n },\n\n getPause = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.pause);\n },\n\n getProgress = function(id) {\n /* jshint eqnull:true */\n // Total progress bar\n if (id == null) {\n return getTemplateEl(container, selectorClasses.totalProgressBarContainer) ||\n getTemplateEl(container, selectorClasses.totalProgressBar);\n }\n\n // Per-file progress bar\n return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) ||\n getTemplateEl(getFile(id), selectorClasses.progressBar);\n },\n\n getRetry = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.retry);\n },\n\n getSize = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.size);\n },\n\n getSpinner = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.spinner);\n },\n\n getTemplateEl = function(context, cssClass) {\n return context && qq(context).getFirstByClass(cssClass);\n },\n\n getThumbnail = function(id) {\n return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);\n },\n\n hide = function(el) {\n el && qq(el).addClass(options.classes.hide);\n },\n\n // Ensures a placeholder image does not exceed any max size specified\n // via `style` attribute properties iff was not used to scale\n // the placeholder AND the target doesn't already have these `style` attribute properties set.\n maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {\n var maxWidth = placeholder.style.maxWidth,\n maxHeight = placeholder.style.maxHeight;\n\n if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {\n qq(thumbnail).css({\n maxWidth: maxWidth,\n maxHeight: maxHeight\n });\n }\n },\n\n // Displays a \"thumbnail not available\" type placeholder image\n // iff we were able to load this placeholder during initialization\n // of the templating module or after preview generation has failed.\n maybeSetDisplayNotAvailableImg = function(id, thumbnail) {\n var previewing = previewGeneration[id] || new qq.Promise().failure(),\n notAvailableImgPlacement = new qq.Promise();\n\n cachedThumbnailNotAvailableImg.then(function(img) {\n previewing.then(\n function() {\n notAvailableImgPlacement.success();\n },\n function() {\n maybeScalePlaceholderViaCss(img, thumbnail);\n\n thumbnail.onload = function() {\n thumbnail.onload = null;\n notAvailableImgPlacement.success();\n };\n\n thumbnail.src = img.src;\n show(thumbnail);\n }\n );\n });\n\n return notAvailableImgPlacement;\n },\n\n /**\n * Grabs the HTML from the script tag holding the template markup. This function will also adjust\n * some internally-tracked state variables based on the contents of the template.\n * The template is filtered so that irrelevant elements (such as the drop zone if DnD is not supported)\n * are omitted from the DOM. Useful errors will be thrown if the template cannot be parsed.\n *\n * @returns {{template: *, fileTemplate: *}} HTML for the top-level file items templates\n */\n parseAndGetTemplate = function() {\n var scriptEl,\n scriptHtml,\n fileListNode,\n tempTemplateEl,\n fileListHtml,\n defaultButton,\n dropArea,\n thumbnail,\n dropProcessing,\n dropTextEl,\n uploaderEl;\n\n log(\"Parsing template\");\n\n /*jshint -W116*/\n if (options.templateIdOrEl == null) {\n throw new Error(\"You MUST specify either a template element or ID!\");\n }\n\n // Grab the contents of the script tag holding the template.\n if (qq.isString(options.templateIdOrEl)) {\n scriptEl = document.getElementById(options.templateIdOrEl);\n\n if (scriptEl === null) {\n throw new Error(qq.format(\"Cannot find template script at ID '{}'!\", options.templateIdOrEl));\n }\n\n scriptHtml = scriptEl.innerHTML;\n }\n else {\n if (options.templateIdOrEl.innerHTML === undefined) {\n throw new Error(\"You have specified an invalid value for the template option! \" +\n \"It must be an ID or an Element.\");\n }\n\n scriptHtml = options.templateIdOrEl.innerHTML;\n }\n\n scriptHtml = qq.trimStr(scriptHtml);\n tempTemplateEl = document.createElement(\"div\");\n tempTemplateEl.appendChild(qq.toElement(scriptHtml));\n uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);\n\n // Don't include the default template button in the DOM\n // if an alternate button container has been specified.\n if (options.button) {\n defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);\n if (defaultButton) {\n qq(defaultButton).remove();\n }\n }\n\n // Omit the drop processing element from the DOM if DnD is not supported by the UA,\n // or the drag and drop module is not found.\n // NOTE: We are consciously not removing the drop zone if the UA doesn't support DnD\n // to support layouts where the drop zone is also a container for visible elements,\n // such as the file list.\n if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {\n dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);\n if (dropProcessing) {\n qq(dropProcessing).remove();\n }\n }\n\n dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);\n\n // If DnD is not available then remove\n // it from the DOM as well.\n if (dropArea && !qq.DragAndDrop) {\n log(\"DnD module unavailable.\", \"info\");\n qq(dropArea).remove();\n }\n\n if (!qq.supportedFeatures.fileDrop) {\n // don't display any \"drop files to upload\" background text\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {\n // If there is a drop area defined in the template, and the current UA doesn't support DnD,\n // and the drop area is marked as \"hide before enter\", ensure it is hidden as the DnD module\n // will not do this (since we will not be loading the DnD module)\n qq(dropArea).css({\n display: \"none\"\n });\n }\n }\n else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {\n dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);\n dropTextEl && qq(dropTextEl).remove();\n }\n\n // Ensure the `showThumbnails` flag is only set if the thumbnail element\n // is present in the template AND the current UA is capable of generating client-side previews.\n thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);\n if (!showThumbnails) {\n thumbnail && qq(thumbnail).remove();\n }\n else if (thumbnail) {\n thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));\n // Only enforce max size if the attr value is non-zero\n thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;\n\n serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);\n }\n showThumbnails = showThumbnails && thumbnail;\n\n isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;\n isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;\n\n fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);\n /*jshint -W116*/\n if (fileListNode == null) {\n throw new Error(\"Could not find the file list container in the template!\");\n }\n\n fileListHtml = fileListNode.innerHTML;\n fileListNode.innerHTML = \"\";\n\n // We must call `createElement` in IE8 in order to target and hide any via CSS\n if (tempTemplateEl.getElementsByTagName(\"DIALOG\").length) {\n document.createElement(\"dialog\");\n }\n\n log(\"Template parsing complete\");\n\n return {\n template: qq.trimStr(tempTemplateEl.innerHTML),\n fileTemplate: qq.trimStr(fileListHtml)\n };\n },\n\n prependFile = function(el, index, fileList) {\n var parentEl = fileList,\n beforeEl = parentEl.firstChild;\n\n if (index > 0) {\n beforeEl = qq(parentEl).children()[index].nextSibling;\n\n }\n\n parentEl.insertBefore(el, beforeEl);\n },\n\n processNewQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n optFileOrBlob = queuedThumbRequest.optFileOrBlob,\n relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n maxSize: thumbnailMaxSize,\n orient: true,\n scale: true\n };\n\n if (qq.supportedFeatures.imagePreviews) {\n if (thumbnail) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n displayWaitingImg(thumbnail).done(function() {\n previewGeneration[id] = new qq.Promise();\n\n previewGeneration[id].done(function() {\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n });\n\n /* jshint eqnull: true */\n // If we've already generated an for this file, use the one that exists,\n // don't waste resources generating a new one.\n if (relatedThumbnailId != null) {\n useCachedPreview(id, relatedThumbnailId);\n }\n else {\n generateNewPreview(id, optFileOrBlob, spec);\n }\n });\n }\n }\n // File element in template may have been removed, so move on to next item in queue\n else {\n generateNextQueuedPreview();\n }\n }\n else if (thumbnail) {\n displayWaitingImg(thumbnail);\n generateNextQueuedPreview();\n }\n },\n\n processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n thumbnailUrl = queuedThumbRequest.thumbnailUrl,\n showWaitingImg = queuedThumbRequest.showWaitingImg,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n scale: serverScale,\n maxSize: thumbnailMaxSize\n };\n\n if (thumbnail) {\n if (thumbnailUrl) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n if (showWaitingImg) {\n displayWaitingImg(thumbnail);\n }\n\n return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(\n function() {\n show(thumbnail);\n generatedThumbnails++;\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n },\n\n function() {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n }\n );\n }\n }\n else {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n }\n },\n\n setProgressBarWidth = function(id, percent) {\n var bar = getProgress(id),\n /* jshint eqnull:true */\n progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;\n\n if (bar && !qq(bar).hasClass(progressBarSelector)) {\n bar = qq(bar).getFirstByClass(progressBarSelector);\n }\n\n if (bar) {\n qq(bar).css({width: percent + \"%\"});\n bar.setAttribute(\"aria-valuenow\", percent);\n }\n },\n\n show = function(el) {\n el && qq(el).removeClass(options.classes.hide);\n },\n\n useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {\n var targetThumbnail = getThumbnail(targetThumbnailId),\n cachedThumbnail = getThumbnail(cachedThumbnailId);\n\n log(qq.format(\"ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.\", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));\n\n // Generation of the related thumbnail may still be in progress, so, wait until it is done.\n previewGeneration[cachedThumbnailId].then(function() {\n generatedThumbnails++;\n previewGeneration[targetThumbnailId].success();\n log(qq.format(\"Now using previously generated thumbnail created for ID {} on ID {}.\", cachedThumbnailId, targetThumbnailId));\n targetThumbnail.src = cachedThumbnail.src;\n show(targetThumbnail);\n },\n function() {\n previewGeneration[targetThumbnailId].failure();\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);\n }\n });\n };\n\n qq.extend(options, spec);\n log = options.log;\n\n // No need to worry about conserving CPU or memory on older browsers,\n // since there is no ability to preview, and thumbnail display is primitive and quick.\n if (!qq.supportedFeatures.imagePreviews) {\n options.limits.timeBetweenThumbs = 0;\n options.limits.maxThumbs = 0;\n }\n\n container = options.containerEl;\n showThumbnails = options.imageGenerator !== undefined;\n templateHtml = parseAndGetTemplate();\n\n cacheThumbnailPlaceholders();\n\n qq.extend(this, {\n render: function() {\n log(\"Rendering template in DOM.\");\n\n generatedThumbnails = 0;\n\n container.innerHTML = templateHtml.template;\n hide(getDropProcessing());\n this.hideTotalProgress();\n fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);\n\n log(\"Template rendering complete\");\n },\n\n renderFailure: function(message) {\n var cantRenderEl = qq.toElement(message);\n container.innerHTML = \"\";\n container.appendChild(cantRenderEl);\n },\n\n reset: function() {\n this.render();\n },\n\n clearFiles: function() {\n fileList.innerHTML = \"\";\n },\n\n disableCancel: function() {\n isCancelDisabled = true;\n },\n\n addFile: function(id, name, prependInfo, hideForever, batch) {\n var fileEl = qq.toElement(templateHtml.fileTemplate),\n fileNameEl = getTemplateEl(fileEl, selectorClasses.file),\n uploaderEl = getTemplateEl(container, selectorClasses.uploader),\n fileContainer = batch ? fileBatch.content : fileList,\n thumb;\n\n if (batch) {\n fileBatch.map[id] = fileEl;\n }\n\n qq(fileEl).addClass(FILE_CLASS_PREFIX + id);\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (fileNameEl) {\n qq(fileNameEl).setText(name);\n fileNameEl.setAttribute(\"title\", name);\n }\n\n fileEl.setAttribute(FILE_ID_ATTR, id);\n\n if (prependInfo) {\n prependFile(fileEl, prependInfo.index, fileContainer);\n }\n else {\n fileContainer.appendChild(fileEl);\n }\n\n if (hideForever) {\n fileEl.style.display = \"none\";\n qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);\n }\n else {\n hide(getProgress(id));\n hide(getSize(id));\n hide(getDelete(id));\n hide(getRetry(id));\n hide(getPause(id));\n hide(getContinue(id));\n\n if (isCancelDisabled) {\n this.hideCancel(id);\n }\n\n thumb = getThumbnail(id);\n if (thumb && !thumb.src) {\n cachedWaitingForThumbnailImg.then(function(waitingImg) {\n thumb.src = waitingImg.src;\n if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {\n qq(thumb).css({\n maxHeight: waitingImg.style.maxHeight,\n maxWidth: waitingImg.style.maxWidth\n });\n }\n\n show(thumb);\n });\n }\n }\n },\n\n addFileToCache: function(id, name, prependInfo, hideForever) {\n this.addFile(id, name, prependInfo, hideForever, true);\n },\n\n addCacheToDom: function() {\n fileList.appendChild(fileBatch.content);\n fileBatch.content = document.createDocumentFragment();\n fileBatch.map = {};\n },\n\n removeFile: function(id) {\n qq(getFile(id)).remove();\n },\n\n getFileId: function(el) {\n var currentNode = el;\n\n if (currentNode) {\n /*jshint -W116*/\n while (currentNode.getAttribute(FILE_ID_ATTR) == null) {\n currentNode = currentNode.parentNode;\n }\n\n return parseInt(currentNode.getAttribute(FILE_ID_ATTR));\n }\n },\n\n getFileList: function() {\n return fileList;\n },\n\n markFilenameEditable: function(id) {\n var filename = getFilename(id);\n\n filename && qq(filename).addClass(options.classes.editable);\n },\n\n updateFilename: function(id, name) {\n var filenameEl = getFilename(id);\n\n if (filenameEl) {\n qq(filenameEl).setText(name);\n filenameEl.setAttribute(\"title\", name);\n }\n },\n\n hideFilename: function(id) {\n hide(getFilename(id));\n },\n\n showFilename: function(id) {\n show(getFilename(id));\n },\n\n isFileName: function(el) {\n return qq(el).hasClass(selectorClasses.file);\n },\n\n getButton: function() {\n return options.button || getTemplateEl(container, selectorClasses.button);\n },\n\n hideDropProcessing: function() {\n hide(getDropProcessing());\n },\n\n showDropProcessing: function() {\n show(getDropProcessing());\n },\n\n getDropZone: function() {\n return getTemplateEl(container, selectorClasses.drop);\n },\n\n isEditFilenamePossible: function() {\n return isEditElementsExist;\n },\n\n hideRetry: function(id) {\n hide(getRetry(id));\n },\n\n isRetryPossible: function() {\n return isRetryElementExist;\n },\n\n showRetry: function(id) {\n show(getRetry(id));\n },\n\n getFileContainer: function(id) {\n return getFile(id);\n },\n\n showEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).addClass(options.classes.editable);\n },\n\n isHiddenForever: function(id) {\n return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);\n },\n\n hideEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).removeClass(options.classes.editable);\n },\n\n isEditIcon: function(el) {\n return qq(el).hasClass(selectorClasses.editNameIcon, true);\n },\n\n getEditInput: function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);\n },\n\n isEditInput: function(el) {\n return qq(el).hasClass(selectorClasses.editFilenameInput, true);\n },\n\n updateProgress: function(id, loaded, total) {\n var bar = getProgress(id),\n percent;\n\n if (bar && total > 0) {\n percent = Math.round(loaded / total * 100);\n\n if (percent === 100) {\n hide(bar);\n }\n else {\n show(bar);\n }\n\n setProgressBarWidth(id, percent);\n }\n },\n\n updateTotalProgress: function(loaded, total) {\n this.updateProgress(null, loaded, total);\n },\n\n hideProgress: function(id) {\n var bar = getProgress(id);\n\n bar && hide(bar);\n },\n\n hideTotalProgress: function() {\n this.hideProgress();\n },\n\n resetProgress: function(id) {\n setProgressBarWidth(id, 0);\n this.hideTotalProgress(id);\n },\n\n resetTotalProgress: function() {\n this.resetProgress();\n },\n\n showCancel: function(id) {\n if (!isCancelDisabled) {\n var cancel = getCancel(id);\n\n cancel && qq(cancel).removeClass(options.classes.hide);\n }\n },\n\n hideCancel: function(id) {\n hide(getCancel(id));\n },\n\n isCancel: function(el) {\n return qq(el).hasClass(selectorClasses.cancel, true);\n },\n\n allowPause: function(id) {\n show(getPause(id));\n hide(getContinue(id));\n },\n\n uploadPaused: function(id) {\n this.setStatusText(id, options.text.paused);\n this.allowContinueButton(id);\n hide(getSpinner(id));\n },\n\n hidePause: function(id) {\n hide(getPause(id));\n },\n\n isPause: function(el) {\n return qq(el).hasClass(selectorClasses.pause, true);\n },\n\n isContinueButton: function(el) {\n return qq(el).hasClass(selectorClasses.continueButton, true);\n },\n\n allowContinueButton: function(id) {\n show(getContinue(id));\n hide(getPause(id));\n },\n\n uploadContinued: function(id) {\n this.setStatusText(id, \"\");\n this.allowPause(id);\n show(getSpinner(id));\n },\n\n showDeleteButton: function(id) {\n show(getDelete(id));\n },\n\n hideDeleteButton: function(id) {\n hide(getDelete(id));\n },\n\n isDeleteButton: function(el) {\n return qq(el).hasClass(selectorClasses.deleteButton, true);\n },\n\n isRetry: function(el) {\n return qq(el).hasClass(selectorClasses.retry, true);\n },\n\n updateSize: function(id, text) {\n var size = getSize(id);\n\n if (size) {\n show(size);\n qq(size).setText(text);\n }\n },\n\n setStatusText: function(id, text) {\n var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);\n\n if (textEl) {\n /*jshint -W116*/\n if (text == null) {\n qq(textEl).clearText();\n }\n else {\n qq(textEl).setText(text);\n }\n }\n },\n\n hideSpinner: function(id) {\n qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);\n hide(getSpinner(id));\n },\n\n showSpinner: function(id) {\n qq(getFile(id)).addClass(IN_PROGRESS_CLASS);\n show(getSpinner(id));\n },\n\n generatePreview: function(id, optFileOrBlob, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({id: id, customResizeFunction: customResizeFunction, optFileOrBlob: optFileOrBlob});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({customResizeFunction: customResizeFunction, update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n hasDialog: function(type) {\n return qq.supportedFeatures.dialogElement && !!getDialog(type);\n },\n\n showDialog: function(type, message, defaultValue) {\n var dialog = getDialog(type),\n messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage),\n inputEl = dialog.getElementsByTagName(\"INPUT\")[0],\n cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton),\n okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton),\n promise = new qq.Promise(),\n\n closeHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.removeEventListener(\"click\", okClickHandler);\n promise.failure();\n },\n\n cancelClickHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n dialog.close();\n },\n\n okClickHandler = function() {\n dialog.removeEventListener(\"close\", closeHandler);\n okBtn.removeEventListener(\"click\", okClickHandler);\n dialog.close();\n\n promise.success(inputEl && inputEl.value);\n };\n\n dialog.addEventListener(\"close\", closeHandler);\n cancelBtn.addEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.addEventListener(\"click\", okClickHandler);\n\n if (inputEl) {\n inputEl.value = defaultValue;\n }\n messageEl.textContent = message;\n\n dialog.showModal();\n\n return promise;\n }\n });\n};\n","/*globals qq */\n// Base handler for UI (FineUploader mode) events.\n// Some more specific handlers inherit from this one.\nqq.UiEventHandler = function(s, protectedApi) {\n \"use strict\";\n\n var disposer = new qq.DisposeSupport(),\n spec = {\n eventType: \"click\",\n attachTo: null,\n onHandled: function(target, event) {}\n };\n\n // This makes up the \"public\" API methods that will be accessible\n // to instances constructing a base or child handler\n qq.extend(this, {\n addHandler: function(element) {\n addHandler(element);\n },\n\n dispose: function() {\n disposer.dispose();\n }\n });\n\n function addHandler(element) {\n disposer.attach(element, spec.eventType, function(event) {\n // Only in IE: the `event` is a property of the `window`.\n event = event || window.event;\n\n // On older browsers, we must check the `srcElement` instead of the `target`.\n var target = event.target || event.srcElement;\n\n spec.onHandled(target, event);\n });\n }\n\n // These make up the \"protected\" API methods that children of this base handler will utilize.\n qq.extend(protectedApi, {\n getFileIdFromItem: function(item) {\n return item.qqFileId;\n },\n\n getDisposeSupport: function() {\n return disposer;\n }\n });\n\n qq.extend(spec, s);\n\n if (spec.attachTo) {\n addHandler(spec.attachTo);\n }\n};\n","/* global qq */\nqq.FileButtonsClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n onDeleteFile: function(fileId) {},\n onCancel: function(fileId) {},\n onRetry: function(fileId) {},\n onPause: function(fileId) {},\n onContinue: function(fileId) {},\n onGetName: function(fileId) {}\n },\n buttonHandlers = {\n cancel: function(id) { spec.onCancel(id); },\n retry: function(id) { spec.onRetry(id); },\n deleteButton: function(id) { spec.onDeleteFile(id); },\n pause: function(id) { spec.onPause(id); },\n continueButton: function(id) { spec.onContinue(id); }\n };\n\n function examineEvent(target, event) {\n qq.each(buttonHandlers, function(buttonType, handler) {\n var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1),\n fileId;\n\n if (spec.templating[\"is\" + firstLetterCapButtonType](target)) {\n fileId = spec.templating.getFileId(target);\n qq.preventDefault(event);\n spec.log(qq.format(\"Detected valid file button click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n handler(fileId);\n return false;\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect click events on filename display elements.\nqq.FilenameClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n classes: {\n file: \"qq-upload-file\",\n editNameIcon: \"qq-edit-filename-icon\"\n },\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {}\n };\n\n qq.extend(spec, s);\n\n // This will be called by the parent handler when a `click` event is received on the list element.\n function examineEvent(target, event) {\n if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n // We only allow users to change filenames of files that have been submitted but not yet uploaded.\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n qq.preventDefault(event);\n\n inheritedInternalApi.handleFilenameEdit(fileId, target, true);\n }\n }\n }\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect focusin events on file edit input elements.\nqq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n onGetUploadStatus: function(fileId) {},\n log: function(message, lvl) {}\n };\n\n if (!inheritedInternalApi) {\n inheritedInternalApi = {};\n }\n\n // This will be called by the parent handler when a `focusin` event is received on the list element.\n function handleInputFocus(target, event) {\n if (spec.templating.isEditInput(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename input focus event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n inheritedInternalApi.handleFilenameEdit(fileId, target);\n }\n }\n }\n\n spec.eventType = \"focusin\";\n spec.onHandled = handleInputFocus;\n\n qq.extend(spec, s);\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n/**\n * Child of FilenameInputFocusInHandler. Used to detect focus events on file edit input elements. This child module is only\n * needed for UAs that do not support the focusin event. Currently, only Firefox lacks this event.\n *\n * @param spec Overrides for default specifications\n */\nqq.FilenameInputFocusHandler = function(spec) {\n \"use strict\";\n\n spec.eventType = \"focus\";\n spec.attachTo = null;\n\n qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));\n};\n","/*globals qq */\n// Handles edit-related events on a file item (FineUploader mode). This is meant to be a parent handler.\n// Children will delegate to this handler when specific edit-related actions are detected.\nqq.FilenameEditHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n log: function(message, lvl) {},\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {},\n onSetName: function(fileId, newName) {},\n onEditingStatusChange: function(fileId, isEditing) {}\n };\n\n function getFilenameSansExtension(fileId) {\n var filenameSansExt = spec.onGetName(fileId),\n extIdx = filenameSansExt.lastIndexOf(\".\");\n\n if (extIdx > 0) {\n filenameSansExt = filenameSansExt.substr(0, extIdx);\n }\n\n return filenameSansExt;\n }\n\n function getOriginalExtension(fileId) {\n var origName = spec.onGetName(fileId);\n return qq.getExtension(origName);\n }\n\n // Callback iff the name has been changed\n function handleNameUpdate(newFilenameInputEl, fileId) {\n var newName = newFilenameInputEl.value,\n origExtension;\n\n if (newName !== undefined && qq.trimStr(newName).length > 0) {\n origExtension = getOriginalExtension(fileId);\n\n if (origExtension !== undefined) {\n newName = newName + \".\" + origExtension;\n }\n\n spec.onSetName(fileId, newName);\n }\n\n spec.onEditingStatusChange(fileId, false);\n }\n\n // The name has been updated if the filename edit input loses focus.\n function registerInputBlurHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"blur\", function() {\n handleNameUpdate(inputEl, fileId);\n });\n }\n\n // The name has been updated if the user presses enter.\n function registerInputEnterKeyHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"keyup\", function(event) {\n\n var code = event.keyCode || event.which;\n\n if (code === 13) {\n handleNameUpdate(inputEl, fileId);\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n\n qq.extend(inheritedInternalApi, {\n handleFilenameEdit: function(id, target, focusInput) {\n var newFilenameInputEl = spec.templating.getEditInput(id);\n\n spec.onEditingStatusChange(id, true);\n\n newFilenameInputEl.value = getFilenameSansExtension(id);\n\n if (focusInput) {\n newFilenameInputEl.focus();\n }\n\n registerInputBlurHandler(newFilenameInputEl, id);\n registerInputEnterKeyHandler(newFilenameInputEl, id);\n }\n });\n};\n","/*globals qq */\n/**\n * This defines FineUploader mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader as well as code to handle uploads directly to Azure.\n * This module inherits all logic from UI & core mode and adds some UI-related logic\n * specific to the upload-to-Azure workflow. Some inherited options and API methods have a special meaning\n * in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploader = function(o) {\n var options = {\n failedUploadTextDisplay: {\n mode: \"custom\"\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Inherit instance data from FineUploader, which should in turn inherit from azure.FineUploaderBasic.\n qq.FineUploader.call(this, options, \"azure\");\n };\n\n // Inherit the API methods from FineUploaderBasicS3\n qq.extend(qq.azure.FineUploader.prototype, qq.azure.FineUploaderBasic.prototype);\n\n // Inherit public and private API methods related to UI\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPublicApi);\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploader.prototype, {\n });\n}());\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.js b/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.js
new file mode 100644
index 000000000000..0fabe09749bd
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.js
@@ -0,0 +1,8196 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+(function(global) {
+ (function($) {
+ "use strict";
+ var $el, pluginOptions = [ "uploaderType", "endpointType" ];
+ function init(options) {
+ var xformedOpts = transformVariables(options || {}), newUploaderInstance = getNewUploaderInstance(xformedOpts);
+ uploader(newUploaderInstance);
+ addCallbacks(xformedOpts, newUploaderInstance);
+ return $el;
+ }
+ function getNewUploaderInstance(params) {
+ var uploaderType = pluginOption("uploaderType"), namespace = pluginOption("endpointType");
+ if (uploaderType) {
+ uploaderType = uploaderType.charAt(0).toUpperCase() + uploaderType.slice(1).toLowerCase();
+ if (namespace) {
+ return new qq[namespace]["FineUploader" + uploaderType](params);
+ }
+ return new qq["FineUploader" + uploaderType](params);
+ } else {
+ if (namespace) {
+ return new qq[namespace].FineUploader(params);
+ }
+ return new qq.FineUploader(params);
+ }
+ }
+ function dataStore(key, val) {
+ var data = $el.data("fineuploader");
+ if (val) {
+ if (data === undefined) {
+ data = {};
+ }
+ data[key] = val;
+ $el.data("fineuploader", data);
+ } else {
+ if (data === undefined) {
+ return null;
+ }
+ return data[key];
+ }
+ }
+ function uploader(instanceToStore) {
+ return dataStore("uploader", instanceToStore);
+ }
+ function pluginOption(option, optionVal) {
+ return dataStore(option, optionVal);
+ }
+ function addCallbacks(transformedOpts, newUploaderInstance) {
+ var callbacks = transformedOpts.callbacks = {};
+ $.each(newUploaderInstance._options.callbacks, function(prop, nonJqueryCallback) {
+ var name, callbackEventTarget;
+ name = /^on(\w+)/.exec(prop)[1];
+ name = name.substring(0, 1).toLowerCase() + name.substring(1);
+ callbackEventTarget = $el;
+ callbacks[prop] = function() {
+ var originalArgs = Array.prototype.slice.call(arguments), transformedArgs = [], nonJqueryCallbackRetVal, jqueryEventCallbackRetVal;
+ $.each(originalArgs, function(idx, arg) {
+ transformedArgs.push(maybeWrapInJquery(arg));
+ });
+ nonJqueryCallbackRetVal = nonJqueryCallback.apply(this, originalArgs);
+ try {
+ jqueryEventCallbackRetVal = callbackEventTarget.triggerHandler(name, transformedArgs);
+ } catch (error) {
+ qq.log("Caught error in Fine Uploader jQuery event handler: " + error.message, "error");
+ }
+ if (nonJqueryCallbackRetVal != null) {
+ return nonJqueryCallbackRetVal;
+ }
+ return jqueryEventCallbackRetVal;
+ };
+ });
+ newUploaderInstance._options.callbacks = callbacks;
+ }
+ function transformVariables(source, dest) {
+ var xformed, arrayVals;
+ if (dest === undefined) {
+ if (source.uploaderType !== "basic") {
+ xformed = {
+ element: $el[0]
+ };
+ } else {
+ xformed = {};
+ }
+ } else {
+ xformed = dest;
+ }
+ $.each(source, function(prop, val) {
+ if ($.inArray(prop, pluginOptions) >= 0) {
+ pluginOption(prop, val);
+ } else if (val instanceof $) {
+ xformed[prop] = val[0];
+ } else if ($.isPlainObject(val)) {
+ xformed[prop] = {};
+ transformVariables(val, xformed[prop]);
+ } else if ($.isArray(val)) {
+ arrayVals = [];
+ $.each(val, function(idx, arrayVal) {
+ var arrayObjDest = {};
+ if (arrayVal instanceof $) {
+ $.merge(arrayVals, arrayVal);
+ } else if ($.isPlainObject(arrayVal)) {
+ transformVariables(arrayVal, arrayObjDest);
+ arrayVals.push(arrayObjDest);
+ } else {
+ arrayVals.push(arrayVal);
+ }
+ });
+ xformed[prop] = arrayVals;
+ } else {
+ xformed[prop] = val;
+ }
+ });
+ if (dest === undefined) {
+ return xformed;
+ }
+ }
+ function isValidCommand(command) {
+ return $.type(command) === "string" && !command.match(/^_/) && uploader()[command] !== undefined;
+ }
+ function delegateCommand(command) {
+ var xformedArgs = [], origArgs = Array.prototype.slice.call(arguments, 1), retVal;
+ transformVariables(origArgs, xformedArgs);
+ retVal = uploader()[command].apply(uploader(), xformedArgs);
+ return maybeWrapInJquery(retVal);
+ }
+ function maybeWrapInJquery(val) {
+ var transformedVal = val;
+ if (val != null && typeof val === "object" && (val.nodeType === 1 || val.nodeType === 9) && val.cloneNode) {
+ transformedVal = $(val);
+ }
+ return transformedVal;
+ }
+ $.fn.fineUploader = function(optionsOrCommand) {
+ var self = this, selfArgs = arguments, retVals = [];
+ this.each(function(index, el) {
+ $el = $(el);
+ if (uploader() && isValidCommand(optionsOrCommand)) {
+ retVals.push(delegateCommand.apply(self, selfArgs));
+ if (self.length === 1) {
+ return false;
+ }
+ } else if (typeof optionsOrCommand === "object" || !optionsOrCommand) {
+ init.apply(self, selfArgs);
+ } else {
+ $.error("Method " + optionsOrCommand + " does not exist on jQuery.fineUploader");
+ }
+ });
+ if (retVals.length === 1) {
+ return retVals[0];
+ } else if (retVals.length > 1) {
+ return retVals;
+ }
+ return this;
+ };
+ })(jQuery);
+ (function($) {
+ "use strict";
+ var rootDataKey = "fineUploaderDnd", $el;
+ function init(options) {
+ if (!options) {
+ options = {};
+ }
+ options.dropZoneElements = [ $el ];
+ var xformedOpts = transformVariables(options);
+ addCallbacks(xformedOpts);
+ dnd(new qq.DragAndDrop(xformedOpts));
+ return $el;
+ }
+ function dataStore(key, val) {
+ var data = $el.data(rootDataKey);
+ if (val) {
+ if (data === undefined) {
+ data = {};
+ }
+ data[key] = val;
+ $el.data(rootDataKey, data);
+ } else {
+ if (data === undefined) {
+ return null;
+ }
+ return data[key];
+ }
+ }
+ function dnd(instanceToStore) {
+ return dataStore("dndInstance", instanceToStore);
+ }
+ function addCallbacks(transformedOpts) {
+ var callbacks = transformedOpts.callbacks = {};
+ $.each(new qq.DragAndDrop.callbacks(), function(prop, func) {
+ var name = prop, $callbackEl;
+ $callbackEl = $el;
+ callbacks[prop] = function() {
+ var args = Array.prototype.slice.call(arguments), jqueryHandlerResult = $callbackEl.triggerHandler(name, args);
+ return jqueryHandlerResult;
+ };
+ });
+ }
+ function transformVariables(source, dest) {
+ var xformed, arrayVals;
+ if (dest === undefined) {
+ xformed = {};
+ } else {
+ xformed = dest;
+ }
+ $.each(source, function(prop, val) {
+ if (val instanceof $) {
+ xformed[prop] = val[0];
+ } else if ($.isPlainObject(val)) {
+ xformed[prop] = {};
+ transformVariables(val, xformed[prop]);
+ } else if ($.isArray(val)) {
+ arrayVals = [];
+ $.each(val, function(idx, arrayVal) {
+ if (arrayVal instanceof $) {
+ $.merge(arrayVals, arrayVal);
+ } else {
+ arrayVals.push(arrayVal);
+ }
+ });
+ xformed[prop] = arrayVals;
+ } else {
+ xformed[prop] = val;
+ }
+ });
+ if (dest === undefined) {
+ return xformed;
+ }
+ }
+ function isValidCommand(command) {
+ return $.type(command) === "string" && command === "dispose" && dnd()[command] !== undefined;
+ }
+ function delegateCommand(command) {
+ var xformedArgs = [], origArgs = Array.prototype.slice.call(arguments, 1);
+ transformVariables(origArgs, xformedArgs);
+ return dnd()[command].apply(dnd(), xformedArgs);
+ }
+ $.fn.fineUploaderDnd = function(optionsOrCommand) {
+ var self = this, selfArgs = arguments, retVals = [];
+ this.each(function(index, el) {
+ $el = $(el);
+ if (dnd() && isValidCommand(optionsOrCommand)) {
+ retVals.push(delegateCommand.apply(self, selfArgs));
+ if (self.length === 1) {
+ return false;
+ }
+ } else if (typeof optionsOrCommand === "object" || !optionsOrCommand) {
+ init.apply(self, selfArgs);
+ } else {
+ $.error("Method " + optionsOrCommand + " does not exist in Fine Uploader's DnD module.");
+ }
+ });
+ if (retVals.length === 1) {
+ return retVals[0];
+ } else if (retVals.length > 1) {
+ return retVals;
+ }
+ return this;
+ };
+ })(jQuery);
+ (function($) {
+ "use strict";
+ $.fn.fineUploaderAzure = function(optionsOrCommand) {
+ if (typeof optionsOrCommand === "object") {
+ optionsOrCommand.endpointType = "azure";
+ }
+ return $.fn.fineUploader.apply(this, arguments);
+ };
+ })(jQuery);
+ var qq = function(element) {
+ "use strict";
+ return {
+ hide: function() {
+ element.style.display = "none";
+ return this;
+ },
+ attach: function(type, fn) {
+ if (element.addEventListener) {
+ element.addEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.attachEvent("on" + type, fn);
+ }
+ return function() {
+ qq(element).detach(type, fn);
+ };
+ },
+ detach: function(type, fn) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.detachEvent("on" + type, fn);
+ }
+ return this;
+ },
+ contains: function(descendant) {
+ if (!descendant) {
+ return false;
+ }
+ if (element === descendant) {
+ return true;
+ }
+ if (element.contains) {
+ return element.contains(descendant);
+ } else {
+ return !!(descendant.compareDocumentPosition(element) & 8);
+ }
+ },
+ insertBefore: function(elementB) {
+ elementB.parentNode.insertBefore(element, elementB);
+ return this;
+ },
+ remove: function() {
+ element.parentNode.removeChild(element);
+ return this;
+ },
+ css: function(styles) {
+ if (element.style == null) {
+ throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");
+ }
+ if (styles.opacity != null) {
+ if (typeof element.style.opacity !== "string" && typeof element.filters !== "undefined") {
+ styles.filter = "alpha(opacity=" + Math.round(100 * styles.opacity) + ")";
+ }
+ }
+ qq.extend(element.style, styles);
+ return this;
+ },
+ hasClass: function(name, considerParent) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));
+ },
+ addClass: function(name) {
+ if (!qq(element).hasClass(name)) {
+ element.className += " " + name;
+ }
+ return this;
+ },
+ removeClass: function(name) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ element.className = element.className.replace(re, " ").replace(/^\s+|\s+$/g, "");
+ return this;
+ },
+ getByClass: function(className, first) {
+ var candidates, result = [];
+ if (first && element.querySelector) {
+ return element.querySelector("." + className);
+ } else if (element.querySelectorAll) {
+ return element.querySelectorAll("." + className);
+ }
+ candidates = element.getElementsByTagName("*");
+ qq.each(candidates, function(idx, val) {
+ if (qq(val).hasClass(className)) {
+ result.push(val);
+ }
+ });
+ return first ? result[0] : result;
+ },
+ getFirstByClass: function(className) {
+ return qq(element).getByClass(className, true);
+ },
+ children: function() {
+ var children = [], child = element.firstChild;
+ while (child) {
+ if (child.nodeType === 1) {
+ children.push(child);
+ }
+ child = child.nextSibling;
+ }
+ return children;
+ },
+ setText: function(text) {
+ element.innerText = text;
+ element.textContent = text;
+ return this;
+ },
+ clearText: function() {
+ return qq(element).setText("");
+ },
+ hasAttribute: function(attrName) {
+ var attrVal;
+ if (element.hasAttribute) {
+ if (!element.hasAttribute(attrName)) {
+ return false;
+ }
+ return /^false$/i.exec(element.getAttribute(attrName)) == null;
+ } else {
+ attrVal = element[attrName];
+ if (attrVal === undefined) {
+ return false;
+ }
+ return /^false$/i.exec(attrVal) == null;
+ }
+ }
+ };
+ };
+ (function() {
+ "use strict";
+ qq.canvasToBlob = function(canvas, mime, quality) {
+ return qq.dataUriToBlob(canvas.toDataURL(mime, quality));
+ };
+ qq.dataUriToBlob = function(dataUri) {
+ var arrayBuffer, byteString, createBlob = function(data, mime) {
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }, intArray, mimeString;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return createBlob(arrayBuffer, mimeString);
+ };
+ qq.log = function(message, level) {
+ if (window.console) {
+ if (!level || level === "info") {
+ window.console.log(message);
+ } else {
+ if (window.console[level]) {
+ window.console[level](message);
+ } else {
+ window.console.log("<" + level + "> " + message);
+ }
+ }
+ }
+ };
+ qq.isObject = function(variable) {
+ return variable && !variable.nodeType && Object.prototype.toString.call(variable) === "[object Object]";
+ };
+ qq.isFunction = function(variable) {
+ return typeof variable === "function";
+ };
+ qq.isArray = function(value) {
+ return Object.prototype.toString.call(value) === "[object Array]" || value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer;
+ };
+ qq.isItemList = function(maybeItemList) {
+ return Object.prototype.toString.call(maybeItemList) === "[object DataTransferItemList]";
+ };
+ qq.isNodeList = function(maybeNodeList) {
+ return Object.prototype.toString.call(maybeNodeList) === "[object NodeList]" || maybeNodeList.item && maybeNodeList.namedItem;
+ };
+ qq.isString = function(maybeString) {
+ return Object.prototype.toString.call(maybeString) === "[object String]";
+ };
+ qq.trimStr = function(string) {
+ if (String.prototype.trim) {
+ return string.trim();
+ }
+ return string.replace(/^\s+|\s+$/g, "");
+ };
+ qq.format = function(str) {
+ var args = Array.prototype.slice.call(arguments, 1), newStr = str, nextIdxToReplace = newStr.indexOf("{}");
+ qq.each(args, function(idx, val) {
+ var strBefore = newStr.substring(0, nextIdxToReplace), strAfter = newStr.substring(nextIdxToReplace + 2);
+ newStr = strBefore + val + strAfter;
+ nextIdxToReplace = newStr.indexOf("{}", nextIdxToReplace + val.length);
+ if (nextIdxToReplace < 0) {
+ return false;
+ }
+ });
+ return newStr;
+ };
+ qq.isFile = function(maybeFile) {
+ return window.File && Object.prototype.toString.call(maybeFile) === "[object File]";
+ };
+ qq.isFileList = function(maybeFileList) {
+ return window.FileList && Object.prototype.toString.call(maybeFileList) === "[object FileList]";
+ };
+ qq.isFileOrInput = function(maybeFileOrInput) {
+ return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);
+ };
+ qq.isInput = function(maybeInput, notFile) {
+ var evaluateType = function(type) {
+ var normalizedType = type.toLowerCase();
+ if (notFile) {
+ return normalizedType !== "file";
+ }
+ return normalizedType === "file";
+ };
+ if (window.HTMLInputElement) {
+ if (Object.prototype.toString.call(maybeInput) === "[object HTMLInputElement]") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ if (maybeInput.tagName) {
+ if (maybeInput.tagName.toLowerCase() === "input") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ qq.isBlob = function(maybeBlob) {
+ if (window.Blob && Object.prototype.toString.call(maybeBlob) === "[object Blob]") {
+ return true;
+ }
+ };
+ qq.isXhrUploadSupported = function() {
+ var input = document.createElement("input");
+ input.type = "file";
+ return input.multiple !== undefined && typeof File !== "undefined" && typeof FormData !== "undefined" && typeof qq.createXhrInstance().upload !== "undefined";
+ };
+ qq.createXhrInstance = function() {
+ if (window.XMLHttpRequest) {
+ return new XMLHttpRequest();
+ }
+ try {
+ return new ActiveXObject("MSXML2.XMLHTTP.3.0");
+ } catch (error) {
+ qq.log("Neither XHR or ActiveX are supported!", "error");
+ return null;
+ }
+ };
+ qq.isFolderDropSupported = function(dataTransfer) {
+ return dataTransfer.items && dataTransfer.items.length > 0 && dataTransfer.items[0].webkitGetAsEntry;
+ };
+ qq.isFileChunkingSupported = function() {
+ return !qq.androidStock() && qq.isXhrUploadSupported() && (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);
+ };
+ qq.sliceBlob = function(fileOrBlob, start, end) {
+ var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;
+ return slicer.call(fileOrBlob, start, end);
+ };
+ qq.arrayBufferToHex = function(buffer) {
+ var bytesAsHex = "", bytes = new Uint8Array(buffer);
+ qq.each(bytes, function(idx, byt) {
+ var byteAsHexStr = byt.toString(16);
+ if (byteAsHexStr.length < 2) {
+ byteAsHexStr = "0" + byteAsHexStr;
+ }
+ bytesAsHex += byteAsHexStr;
+ });
+ return bytesAsHex;
+ };
+ qq.readBlobToHex = function(blob, startOffset, length) {
+ var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), fileReader = new FileReader(), promise = new qq.Promise();
+ fileReader.onload = function() {
+ promise.success(qq.arrayBufferToHex(fileReader.result));
+ };
+ fileReader.onerror = promise.failure;
+ fileReader.readAsArrayBuffer(initialBlob);
+ return promise;
+ };
+ qq.extend = function(first, second, extendNested) {
+ qq.each(second, function(prop, val) {
+ if (extendNested && qq.isObject(val)) {
+ if (first[prop] === undefined) {
+ first[prop] = {};
+ }
+ qq.extend(first[prop], val, true);
+ } else {
+ first[prop] = val;
+ }
+ });
+ return first;
+ };
+ qq.override = function(target, sourceFn) {
+ var super_ = {}, source = sourceFn(super_);
+ qq.each(source, function(srcPropName, srcPropVal) {
+ if (target[srcPropName] !== undefined) {
+ super_[srcPropName] = target[srcPropName];
+ }
+ target[srcPropName] = srcPropVal;
+ });
+ return target;
+ };
+ qq.indexOf = function(arr, elt, from) {
+ if (arr.indexOf) {
+ return arr.indexOf(elt, from);
+ }
+ from = from || 0;
+ var len = arr.length;
+ if (from < 0) {
+ from += len;
+ }
+ for (;from < len; from += 1) {
+ if (arr.hasOwnProperty(from) && arr[from] === elt) {
+ return from;
+ }
+ }
+ return -1;
+ };
+ qq.getUniqueId = function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
+ return v.toString(16);
+ });
+ };
+ qq.ie = function() {
+ return navigator.userAgent.indexOf("MSIE") !== -1 || navigator.userAgent.indexOf("Trident") !== -1;
+ };
+ qq.ie7 = function() {
+ return navigator.userAgent.indexOf("MSIE 7") !== -1;
+ };
+ qq.ie8 = function() {
+ return navigator.userAgent.indexOf("MSIE 8") !== -1;
+ };
+ qq.ie10 = function() {
+ return navigator.userAgent.indexOf("MSIE 10") !== -1;
+ };
+ qq.ie11 = function() {
+ return qq.ie() && navigator.userAgent.indexOf("rv:11") !== -1;
+ };
+ qq.edge = function() {
+ return navigator.userAgent.indexOf("Edge") >= 0;
+ };
+ qq.safari = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Apple") !== -1;
+ };
+ qq.chrome = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Google") !== -1;
+ };
+ qq.opera = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Opera") !== -1;
+ };
+ qq.firefox = function() {
+ return !qq.edge() && !qq.ie11() && navigator.userAgent.indexOf("Mozilla") !== -1 && navigator.vendor !== undefined && navigator.vendor === "";
+ };
+ qq.windows = function() {
+ return navigator.platform === "Win32";
+ };
+ qq.android = function() {
+ return navigator.userAgent.toLowerCase().indexOf("android") !== -1;
+ };
+ qq.androidStock = function() {
+ return qq.android() && navigator.userAgent.toLowerCase().indexOf("chrome") < 0;
+ };
+ qq.ios6 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 6_") !== -1;
+ };
+ qq.ios7 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 7_") !== -1;
+ };
+ qq.ios8 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_") !== -1;
+ };
+ qq.ios800 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_0 ") !== -1;
+ };
+ qq.ios = function() {
+ return navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("iPod") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1;
+ };
+ qq.iosChrome = function() {
+ return qq.ios() && navigator.userAgent.indexOf("CriOS") !== -1;
+ };
+ qq.iosSafari = function() {
+ return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf("Safari") !== -1;
+ };
+ qq.iosSafariWebView = function() {
+ return qq.ios() && !qq.iosChrome() && !qq.iosSafari();
+ };
+ qq.preventDefault = function(e) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ };
+ qq.toElement = function() {
+ var div = document.createElement("div");
+ return function(html) {
+ div.innerHTML = html;
+ var element = div.firstChild;
+ div.removeChild(element);
+ return element;
+ };
+ }();
+ qq.each = function(iterableItem, callback) {
+ var keyOrIndex, retVal;
+ if (iterableItem) {
+ if (window.Storage && iterableItem.constructor === window.Storage) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isString(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else {
+ for (keyOrIndex in iterableItem) {
+ if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ };
+ qq.bind = function(oldFunc, context) {
+ if (qq.isFunction(oldFunc)) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ return function() {
+ var newArgs = qq.extend([], args);
+ if (arguments.length) {
+ newArgs = newArgs.concat(Array.prototype.slice.call(arguments));
+ }
+ return oldFunc.apply(context, newArgs);
+ };
+ }
+ throw new Error("first parameter must be a function!");
+ };
+ qq.obj2url = function(obj, temp, prefixDone) {
+ var uristrings = [], prefix = "&", add = function(nextObj, i) {
+ var nextTemp = temp ? /\[\]$/.test(temp) ? temp : temp + "[" + i + "]" : i;
+ if (nextTemp !== "undefined" && i !== "undefined") {
+ uristrings.push(typeof nextObj === "object" ? qq.obj2url(nextObj, nextTemp, true) : Object.prototype.toString.call(nextObj) === "[object Function]" ? encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj));
+ }
+ };
+ if (!prefixDone && temp) {
+ prefix = /\?/.test(temp) ? /\?$/.test(temp) ? "" : "&" : "?";
+ uristrings.push(temp);
+ uristrings.push(qq.obj2url(obj));
+ } else if (Object.prototype.toString.call(obj) === "[object Array]" && typeof obj !== "undefined") {
+ qq.each(obj, function(idx, val) {
+ add(val, idx);
+ });
+ } else if (typeof obj !== "undefined" && obj !== null && typeof obj === "object") {
+ qq.each(obj, function(prop, val) {
+ add(val, prop);
+ });
+ } else {
+ uristrings.push(encodeURIComponent(temp) + "=" + encodeURIComponent(obj));
+ }
+ if (temp) {
+ return uristrings.join(prefix);
+ } else {
+ return uristrings.join(prefix).replace(/^&/, "").replace(/%20/g, "+");
+ }
+ };
+ qq.obj2FormData = function(obj, formData, arrayKeyName) {
+ if (!formData) {
+ formData = new FormData();
+ }
+ qq.each(obj, function(key, val) {
+ key = arrayKeyName ? arrayKeyName + "[" + key + "]" : key;
+ if (qq.isObject(val)) {
+ qq.obj2FormData(val, formData, key);
+ } else if (qq.isFunction(val)) {
+ formData.append(key, val());
+ } else {
+ formData.append(key, val);
+ }
+ });
+ return formData;
+ };
+ qq.obj2Inputs = function(obj, form) {
+ var input;
+ if (!form) {
+ form = document.createElement("form");
+ }
+ qq.obj2FormData(obj, {
+ append: function(key, val) {
+ input = document.createElement("input");
+ input.setAttribute("name", key);
+ input.setAttribute("value", val);
+ form.appendChild(input);
+ }
+ });
+ return form;
+ };
+ qq.parseJson = function(json) {
+ if (window.JSON && qq.isFunction(JSON.parse)) {
+ return JSON.parse(json);
+ } else {
+ return eval("(" + json + ")");
+ }
+ };
+ qq.getExtension = function(filename) {
+ var extIdx = filename.lastIndexOf(".") + 1;
+ if (extIdx > 0) {
+ return filename.substr(extIdx, filename.length - extIdx);
+ }
+ };
+ qq.getFilename = function(blobOrFileInput) {
+ if (qq.isInput(blobOrFileInput)) {
+ return blobOrFileInput.value.replace(/.*(\/|\\)/, "");
+ } else if (qq.isFile(blobOrFileInput)) {
+ if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {
+ return blobOrFileInput.fileName;
+ }
+ }
+ return blobOrFileInput.name;
+ };
+ qq.DisposeSupport = function() {
+ var disposers = [];
+ return {
+ dispose: function() {
+ var disposer;
+ do {
+ disposer = disposers.shift();
+ if (disposer) {
+ disposer();
+ }
+ } while (disposer);
+ },
+ attach: function() {
+ var args = arguments;
+ this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));
+ },
+ addDisposer: function(disposeFunction) {
+ disposers.push(disposeFunction);
+ }
+ };
+ };
+ })();
+ (function() {
+ "use strict";
+ if (typeof define === "function" && define.amd) {
+ define(function() {
+ return qq;
+ });
+ } else if (typeof module !== "undefined" && module.exports) {
+ module.exports = qq;
+ } else {
+ global.qq = qq;
+ }
+ })();
+ (function() {
+ "use strict";
+ qq.Error = function(message) {
+ this.message = "[Fine Uploader " + qq.version + "] " + message;
+ };
+ qq.Error.prototype = new Error();
+ })();
+ qq.version = "5.13.0";
+ qq.supportedFeatures = function() {
+ "use strict";
+ var supportsUploading, supportsUploadingBlobs, supportsFileDrop, supportsAjaxFileUploading, supportsFolderDrop, supportsChunking, supportsResume, supportsUploadViaPaste, supportsUploadCors, supportsDeleteFileXdr, supportsDeleteFileCorsXhr, supportsDeleteFileCors, supportsFolderSelection, supportsImagePreviews, supportsUploadProgress;
+ function testSupportsFileInputElement() {
+ var supported = true, tempInput;
+ try {
+ tempInput = document.createElement("input");
+ tempInput.type = "file";
+ qq(tempInput).hide();
+ if (tempInput.disabled) {
+ supported = false;
+ }
+ } catch (ex) {
+ supported = false;
+ }
+ return supported;
+ }
+ function isChrome21OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/) !== undefined;
+ }
+ function isChrome14OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/) !== undefined;
+ }
+ function isCrossOriginXhrSupported() {
+ if (window.XMLHttpRequest) {
+ var xhr = qq.createXhrInstance();
+ return xhr.withCredentials !== undefined;
+ }
+ return false;
+ }
+ function isXdrSupported() {
+ return window.XDomainRequest !== undefined;
+ }
+ function isCrossOriginAjaxSupported() {
+ if (isCrossOriginXhrSupported()) {
+ return true;
+ }
+ return isXdrSupported();
+ }
+ function isFolderSelectionSupported() {
+ return document.createElement("input").webkitdirectory !== undefined;
+ }
+ function isLocalStorageSupported() {
+ try {
+ return !!window.localStorage && qq.isFunction(window.localStorage.setItem);
+ } catch (error) {
+ return false;
+ }
+ }
+ function isDragAndDropSupported() {
+ var span = document.createElement("span");
+ return ("draggable" in span || "ondragstart" in span && "ondrop" in span) && !qq.android() && !qq.ios();
+ }
+ supportsUploading = testSupportsFileInputElement();
+ supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();
+ supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();
+ supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();
+ supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();
+ supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();
+ supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();
+ supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();
+ supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);
+ supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();
+ supportsDeleteFileXdr = isXdrSupported();
+ supportsDeleteFileCors = isCrossOriginAjaxSupported();
+ supportsFolderSelection = isFolderSelectionSupported();
+ supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;
+ supportsUploadProgress = function() {
+ if (supportsAjaxFileUploading) {
+ return !qq.androidStock() && !qq.iosChrome();
+ }
+ return false;
+ }();
+ return {
+ ajaxUploading: supportsAjaxFileUploading,
+ blobUploading: supportsUploadingBlobs,
+ canDetermineSize: supportsAjaxFileUploading,
+ chunking: supportsChunking,
+ deleteFileCors: supportsDeleteFileCors,
+ deleteFileCorsXdr: supportsDeleteFileXdr,
+ deleteFileCorsXhr: supportsDeleteFileCorsXhr,
+ dialogElement: !!window.HTMLDialogElement,
+ fileDrop: supportsFileDrop,
+ folderDrop: supportsFolderDrop,
+ folderSelection: supportsFolderSelection,
+ imagePreviews: supportsImagePreviews,
+ imageValidation: supportsImagePreviews,
+ itemSizeValidation: supportsAjaxFileUploading,
+ pause: supportsChunking,
+ progressBar: supportsUploadProgress,
+ resume: supportsResume,
+ scaling: supportsImagePreviews && supportsUploadingBlobs,
+ tiffPreviews: qq.safari(),
+ unlimitedScaledImageSize: !qq.ios(),
+ uploading: supportsUploading,
+ uploadCors: supportsUploadCors,
+ uploadCustomHeaders: supportsAjaxFileUploading,
+ uploadNonMultipart: supportsAjaxFileUploading,
+ uploadViaPaste: supportsUploadViaPaste
+ };
+ }();
+ qq.isGenericPromise = function(maybePromise) {
+ "use strict";
+ return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));
+ };
+ qq.Promise = function() {
+ "use strict";
+ var successArgs, failureArgs, successCallbacks = [], failureCallbacks = [], doneCallbacks = [], state = 0;
+ qq.extend(this, {
+ then: function(onSuccess, onFailure) {
+ if (state === 0) {
+ if (onSuccess) {
+ successCallbacks.push(onSuccess);
+ }
+ if (onFailure) {
+ failureCallbacks.push(onFailure);
+ }
+ } else if (state === -1) {
+ onFailure && onFailure.apply(null, failureArgs);
+ } else if (onSuccess) {
+ onSuccess.apply(null, successArgs);
+ }
+ return this;
+ },
+ done: function(callback) {
+ if (state === 0) {
+ doneCallbacks.push(callback);
+ } else {
+ callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);
+ }
+ return this;
+ },
+ success: function() {
+ state = 1;
+ successArgs = arguments;
+ if (successCallbacks.length) {
+ qq.each(successCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ return this;
+ },
+ failure: function() {
+ state = -1;
+ failureArgs = arguments;
+ if (failureCallbacks.length) {
+ qq.each(failureCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ return this;
+ }
+ });
+ };
+ qq.BlobProxy = function(referenceBlob, onCreate) {
+ "use strict";
+ qq.extend(this, {
+ referenceBlob: referenceBlob,
+ create: function() {
+ return onCreate(referenceBlob);
+ }
+ });
+ };
+ qq.UploadButton = function(o) {
+ "use strict";
+ var self = this, disposeSupport = new qq.DisposeSupport(), options = {
+ acceptFiles: null,
+ element: null,
+ focusClass: "qq-upload-button-focus",
+ folders: false,
+ hoverClass: "qq-upload-button-hover",
+ ios8BrowserCrashWorkaround: false,
+ multiple: false,
+ name: "qqfile",
+ onChange: function(input) {},
+ title: null
+ }, input, buttonId;
+ qq.extend(options, o);
+ buttonId = qq.getUniqueId();
+ function createInput() {
+ var input = document.createElement("input");
+ input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);
+ input.setAttribute("title", options.title);
+ self.setMultiple(options.multiple, input);
+ if (options.folders && qq.supportedFeatures.folderSelection) {
+ input.setAttribute("webkitdirectory", "");
+ }
+ if (options.acceptFiles) {
+ input.setAttribute("accept", options.acceptFiles);
+ }
+ input.setAttribute("type", "file");
+ input.setAttribute("name", options.name);
+ qq(input).css({
+ position: "absolute",
+ right: 0,
+ top: 0,
+ fontFamily: "Arial",
+ fontSize: qq.ie() && !qq.ie8() ? "3500px" : "118px",
+ margin: 0,
+ padding: 0,
+ cursor: "pointer",
+ opacity: 0
+ });
+ !qq.ie7() && qq(input).css({
+ height: "100%"
+ });
+ options.element.appendChild(input);
+ disposeSupport.attach(input, "change", function() {
+ options.onChange(input);
+ });
+ disposeSupport.attach(input, "mouseover", function() {
+ qq(options.element).addClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "mouseout", function() {
+ qq(options.element).removeClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "focus", function() {
+ qq(options.element).addClass(options.focusClass);
+ });
+ disposeSupport.attach(input, "blur", function() {
+ qq(options.element).removeClass(options.focusClass);
+ });
+ return input;
+ }
+ qq(options.element).css({
+ position: "relative",
+ overflow: "hidden",
+ direction: "ltr"
+ });
+ qq.extend(this, {
+ getInput: function() {
+ return input;
+ },
+ getButtonId: function() {
+ return buttonId;
+ },
+ setMultiple: function(isMultiple, optInput) {
+ var input = optInput || this.getInput();
+ if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {
+ input.setAttribute("multiple", "");
+ } else {
+ if (isMultiple) {
+ input.setAttribute("multiple", "");
+ } else {
+ input.removeAttribute("multiple");
+ }
+ }
+ },
+ setAcceptFiles: function(acceptFiles) {
+ if (acceptFiles !== options.acceptFiles) {
+ input.setAttribute("accept", acceptFiles);
+ }
+ },
+ reset: function() {
+ if (input.parentNode) {
+ qq(input).remove();
+ }
+ qq(options.element).removeClass(options.focusClass);
+ input = null;
+ input = createInput();
+ }
+ });
+ input = createInput();
+ };
+ qq.UploadButton.BUTTON_ID_ATTR_NAME = "qq-button-id";
+ qq.UploadData = function(uploaderProxy) {
+ "use strict";
+ var data = [], byUuid = {}, byStatus = {}, byProxyGroupId = {}, byBatchId = {};
+ function getDataByIds(idOrIds) {
+ if (qq.isArray(idOrIds)) {
+ var entries = [];
+ qq.each(idOrIds, function(idx, id) {
+ entries.push(data[id]);
+ });
+ return entries;
+ }
+ return data[idOrIds];
+ }
+ function getDataByUuids(uuids) {
+ if (qq.isArray(uuids)) {
+ var entries = [];
+ qq.each(uuids, function(idx, uuid) {
+ entries.push(data[byUuid[uuid]]);
+ });
+ return entries;
+ }
+ return data[byUuid[uuids]];
+ }
+ function getDataByStatus(status) {
+ var statusResults = [], statuses = [].concat(status);
+ qq.each(statuses, function(index, statusEnum) {
+ var statusResultIndexes = byStatus[statusEnum];
+ if (statusResultIndexes !== undefined) {
+ qq.each(statusResultIndexes, function(i, dataIndex) {
+ statusResults.push(data[dataIndex]);
+ });
+ }
+ });
+ return statusResults;
+ }
+ qq.extend(this, {
+ addFile: function(spec) {
+ var status = spec.status || qq.status.SUBMITTING, id = data.push({
+ name: spec.name,
+ originalName: spec.name,
+ uuid: spec.uuid,
+ size: spec.size == null ? -1 : spec.size,
+ status: status
+ }) - 1;
+ if (spec.batchId) {
+ data[id].batchId = spec.batchId;
+ if (byBatchId[spec.batchId] === undefined) {
+ byBatchId[spec.batchId] = [];
+ }
+ byBatchId[spec.batchId].push(id);
+ }
+ if (spec.proxyGroupId) {
+ data[id].proxyGroupId = spec.proxyGroupId;
+ if (byProxyGroupId[spec.proxyGroupId] === undefined) {
+ byProxyGroupId[spec.proxyGroupId] = [];
+ }
+ byProxyGroupId[spec.proxyGroupId].push(id);
+ }
+ data[id].id = id;
+ byUuid[spec.uuid] = id;
+ if (byStatus[status] === undefined) {
+ byStatus[status] = [];
+ }
+ byStatus[status].push(id);
+ uploaderProxy.onStatusChange(id, null, status);
+ return id;
+ },
+ retrieve: function(optionalFilter) {
+ if (qq.isObject(optionalFilter) && data.length) {
+ if (optionalFilter.id !== undefined) {
+ return getDataByIds(optionalFilter.id);
+ } else if (optionalFilter.uuid !== undefined) {
+ return getDataByUuids(optionalFilter.uuid);
+ } else if (optionalFilter.status) {
+ return getDataByStatus(optionalFilter.status);
+ }
+ } else {
+ return qq.extend([], data, true);
+ }
+ },
+ reset: function() {
+ data = [];
+ byUuid = {};
+ byStatus = {};
+ byBatchId = {};
+ },
+ setStatus: function(id, newStatus) {
+ var oldStatus = data[id].status, byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);
+ byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);
+ data[id].status = newStatus;
+ if (byStatus[newStatus] === undefined) {
+ byStatus[newStatus] = [];
+ }
+ byStatus[newStatus].push(id);
+ uploaderProxy.onStatusChange(id, oldStatus, newStatus);
+ },
+ uuidChanged: function(id, newUuid) {
+ var oldUuid = data[id].uuid;
+ data[id].uuid = newUuid;
+ byUuid[newUuid] = id;
+ delete byUuid[oldUuid];
+ },
+ updateName: function(id, newName) {
+ data[id].name = newName;
+ },
+ updateSize: function(id, newSize) {
+ data[id].size = newSize;
+ },
+ setParentId: function(targetId, parentId) {
+ data[targetId].parentId = parentId;
+ },
+ getIdsInProxyGroup: function(id) {
+ var proxyGroupId = data[id].proxyGroupId;
+ if (proxyGroupId) {
+ return byProxyGroupId[proxyGroupId];
+ }
+ return [];
+ },
+ getIdsInBatch: function(id) {
+ var batchId = data[id].batchId;
+ return byBatchId[batchId];
+ }
+ });
+ };
+ qq.status = {
+ SUBMITTING: "submitting",
+ SUBMITTED: "submitted",
+ REJECTED: "rejected",
+ QUEUED: "queued",
+ CANCELED: "canceled",
+ PAUSED: "paused",
+ UPLOADING: "uploading",
+ UPLOAD_RETRYING: "retrying upload",
+ UPLOAD_SUCCESSFUL: "upload successful",
+ UPLOAD_FAILED: "upload failed",
+ DELETE_FAILED: "delete failed",
+ DELETING: "deleting",
+ DELETED: "deleted"
+ };
+ (function() {
+ "use strict";
+ qq.basePublicApi = {
+ addBlobs: function(blobDataOrArray, params, endpoint) {
+ this.addFiles(blobDataOrArray, params, endpoint);
+ },
+ addInitialFiles: function(cannedFileList) {
+ var self = this;
+ qq.each(cannedFileList, function(index, cannedFile) {
+ self._addCannedFile(cannedFile);
+ });
+ },
+ addFiles: function(data, params, endpoint) {
+ this._maybeHandleIos8SafariWorkaround();
+ var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId, processBlob = qq.bind(function(blob) {
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName
+ }, batchId, verifiedFiles);
+ }, this), processBlobData = qq.bind(function(blobData) {
+ this._handleNewFile(blobData, batchId, verifiedFiles);
+ }, this), processCanvas = qq.bind(function(canvas) {
+ var blob = qq.canvasToBlob(canvas);
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName + ".png"
+ }, batchId, verifiedFiles);
+ }, this), processCanvasData = qq.bind(function(canvasData) {
+ var normalizedQuality = canvasData.quality && canvasData.quality / 100, blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);
+ this._handleNewFile({
+ blob: blob,
+ name: canvasData.name
+ }, batchId, verifiedFiles);
+ }, this), processFileOrInput = qq.bind(function(fileOrInput) {
+ if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {
+ var files = Array.prototype.slice.call(fileOrInput.files), self = this;
+ qq.each(files, function(idx, file) {
+ self._handleNewFile(file, batchId, verifiedFiles);
+ });
+ } else {
+ this._handleNewFile(fileOrInput, batchId, verifiedFiles);
+ }
+ }, this), normalizeData = function() {
+ if (qq.isFileList(data)) {
+ data = Array.prototype.slice.call(data);
+ }
+ data = [].concat(data);
+ }, self = this, verifiedFiles = [];
+ this._currentBatchId = batchId;
+ if (data) {
+ normalizeData();
+ qq.each(data, function(idx, fileContainer) {
+ if (qq.isFileOrInput(fileContainer)) {
+ processFileOrInput(fileContainer);
+ } else if (qq.isBlob(fileContainer)) {
+ processBlob(fileContainer);
+ } else if (qq.isObject(fileContainer)) {
+ if (fileContainer.blob && fileContainer.name) {
+ processBlobData(fileContainer);
+ } else if (fileContainer.canvas && fileContainer.name) {
+ processCanvasData(fileContainer);
+ }
+ } else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === "canvas") {
+ processCanvas(fileContainer);
+ } else {
+ self.log(fileContainer + " is not a valid file container! Ignoring!", "warn");
+ }
+ });
+ this.log("Received " + verifiedFiles.length + " files.");
+ this._prepareItemsForUpload(verifiedFiles, params, endpoint);
+ }
+ },
+ cancel: function(id) {
+ this._handler.cancel(id);
+ },
+ cancelAll: function() {
+ var storedIdsCopy = [], self = this;
+ qq.extend(storedIdsCopy, this._storedIds);
+ qq.each(storedIdsCopy, function(idx, storedFileId) {
+ self.cancel(storedFileId);
+ });
+ this._handler.cancelAll();
+ },
+ clearStoredFiles: function() {
+ this._storedIds = [];
+ },
+ continueUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (uploadData.status === qq.status.PAUSED) {
+ this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.", id, this.getName(id)));
+ this._uploadFile(id);
+ return true;
+ } else {
+ this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ deleteFile: function(id) {
+ return this._onSubmitDelete(id);
+ },
+ doesExist: function(fileOrBlobId) {
+ return this._handler.isValid(fileOrBlobId);
+ },
+ drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {
+ var promiseToReturn = new qq.Promise(), fileOrUrl, options;
+ if (this._imageGenerator) {
+ fileOrUrl = this._thumbnailUrls[fileId];
+ options = {
+ customResizeFunction: customResizeFunction,
+ maxSize: maxSize > 0 ? maxSize : null,
+ scale: maxSize > 0
+ };
+ if (!fromServer && qq.supportedFeatures.imagePreviews) {
+ fileOrUrl = this.getFile(fileId);
+ }
+ if (fileOrUrl == null) {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "File or URL not found."
+ });
+ } else {
+ this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(function success(modifiedContainer) {
+ promiseToReturn.success(modifiedContainer);
+ }, function failure(container, reason) {
+ promiseToReturn.failure({
+ container: container,
+ error: reason || "Problem generating thumbnail"
+ });
+ });
+ }
+ } else {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "Missing image generator module"
+ });
+ }
+ return promiseToReturn;
+ },
+ getButton: function(fileId) {
+ return this._getButton(this._buttonIdsForFileIds[fileId]);
+ },
+ getEndpoint: function(fileId) {
+ return this._endpointStore.get(fileId);
+ },
+ getFile: function(fileOrBlobId) {
+ return this._handler.getFile(fileOrBlobId) || null;
+ },
+ getInProgress: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED ]
+ }).length;
+ },
+ getName: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).name;
+ },
+ getParentId: function(id) {
+ var uploadDataEntry = this.getUploads({
+ id: id
+ }), parentId = null;
+ if (uploadDataEntry) {
+ if (uploadDataEntry.parentId !== undefined) {
+ parentId = uploadDataEntry.parentId;
+ }
+ }
+ return parentId;
+ },
+ getResumableFilesData: function() {
+ return this._handler.getResumableFilesData();
+ },
+ getSize: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).size;
+ },
+ getNetUploads: function() {
+ return this._netUploaded;
+ },
+ getRemainingAllowedItems: function() {
+ var allowedItems = this._currentItemLimit;
+ if (allowedItems > 0) {
+ return allowedItems - this._netUploadedOrQueued;
+ }
+ return null;
+ },
+ getUploads: function(optionalFilter) {
+ return this._uploadData.retrieve(optionalFilter);
+ },
+ getUuid: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).uuid;
+ },
+ log: function(str, level) {
+ if (this._options.debug && (!level || level === "info")) {
+ qq.log("[Fine Uploader " + qq.version + "] " + str);
+ } else if (level && level !== "info") {
+ qq.log("[Fine Uploader " + qq.version + "] " + str, level);
+ }
+ },
+ pauseUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (qq.indexOf([ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING ], uploadData.status) >= 0) {
+ if (this._handler.pause(id)) {
+ this._uploadData.setStatus(id, qq.status.PAUSED);
+ return true;
+ } else {
+ this.log(qq.format("Unable to pause file ID {} ({}).", id, this.getName(id)), "error");
+ }
+ } else {
+ this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ reset: function() {
+ this.log("Resetting uploader...");
+ this._handler.reset();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ this._paramsStore.reset();
+ this._endpointStore.reset();
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData.reset();
+ this._buttonIdsForFileIds = [];
+ this._pasteHandler && this._pasteHandler.reset();
+ this._options.session.refreshOnReset && this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._totalProgress && this._totalProgress.reset();
+ },
+ retry: function(id) {
+ return this._manualRetry(id);
+ },
+ scaleImage: function(id, specs) {
+ var self = this;
+ return qq.Scaler.prototype.scaleImage(id, specs, {
+ log: qq.bind(self.log, self),
+ getFile: qq.bind(self.getFile, self),
+ uploadData: self._uploadData
+ });
+ },
+ setCustomHeaders: function(headers, id) {
+ this._customHeadersStore.set(headers, id);
+ },
+ setDeleteFileCustomHeaders: function(headers, id) {
+ this._deleteFileCustomHeadersStore.set(headers, id);
+ },
+ setDeleteFileEndpoint: function(endpoint, id) {
+ this._deleteFileEndpointStore.set(endpoint, id);
+ },
+ setDeleteFileParams: function(params, id) {
+ this._deleteFileParamsStore.set(params, id);
+ },
+ setEndpoint: function(endpoint, id) {
+ this._endpointStore.set(endpoint, id);
+ },
+ setForm: function(elementOrId) {
+ this._updateFormSupportAndParams(elementOrId);
+ },
+ setItemLimit: function(newItemLimit) {
+ this._currentItemLimit = newItemLimit;
+ },
+ setName: function(id, newName) {
+ this._uploadData.updateName(id, newName);
+ },
+ setParams: function(params, id) {
+ this._paramsStore.set(params, id);
+ },
+ setUuid: function(id, newUuid) {
+ return this._uploadData.uuidChanged(id, newUuid);
+ },
+ uploadStoredFiles: function() {
+ if (this._storedIds.length === 0) {
+ this._itemError("noFilesError");
+ } else {
+ this._uploadStoredFiles();
+ }
+ }
+ };
+ qq.basePrivateApi = {
+ _addCannedFile: function(sessionData) {
+ var id = this._uploadData.addFile({
+ uuid: sessionData.uuid,
+ name: sessionData.name,
+ size: sessionData.size,
+ status: qq.status.UPLOAD_SUCCESSFUL
+ });
+ sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);
+ sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);
+ if (sessionData.thumbnailUrl) {
+ this._thumbnailUrls[id] = sessionData.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._netUploadedOrQueued++;
+ return id;
+ },
+ _annotateWithButtonId: function(file, associatedInput) {
+ if (qq.isFile(file)) {
+ file.qqButtonId = this._getButtonId(associatedInput);
+ }
+ },
+ _batchError: function(message) {
+ this._options.callbacks.onError(null, null, message, undefined);
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return new qq.DeleteFileAjaxRequester({
+ method: this._options.deleteFile.method.toUpperCase(),
+ maxConnections: this._options.maxConnections,
+ uuidParamName: this._options.request.uuidName,
+ customHeaders: this._deleteFileCustomHeadersStore,
+ paramsStore: this._deleteFileParamsStore,
+ endpointStore: this._deleteFileEndpointStore,
+ cors: this._options.cors,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ });
+ },
+ _createPasteHandler: function() {
+ var self = this;
+ return new qq.PasteSupport({
+ targetElement: this._options.paste.targetElement,
+ callbacks: {
+ log: qq.bind(self.log, self),
+ pasteReceived: function(blob) {
+ self._handleCheckedCallback({
+ name: "onPasteReceived",
+ callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),
+ onSuccess: qq.bind(self._handlePasteSuccess, self, blob),
+ identifier: "pasted image"
+ });
+ }
+ }
+ });
+ },
+ _createStore: function(initialValue, _readOnlyValues_) {
+ var store = {}, catchall = initialValue, perIdReadOnlyValues = {}, readOnlyValues = _readOnlyValues_, copy = function(orig) {
+ if (qq.isObject(orig)) {
+ return qq.extend({}, orig);
+ }
+ return orig;
+ }, getReadOnlyValues = function() {
+ if (qq.isFunction(readOnlyValues)) {
+ return readOnlyValues();
+ }
+ return readOnlyValues;
+ }, includeReadOnlyValues = function(id, existing) {
+ if (readOnlyValues && qq.isObject(existing)) {
+ qq.extend(existing, getReadOnlyValues());
+ }
+ if (perIdReadOnlyValues[id]) {
+ qq.extend(existing, perIdReadOnlyValues[id]);
+ }
+ };
+ return {
+ set: function(val, id) {
+ if (id == null) {
+ store = {};
+ catchall = copy(val);
+ } else {
+ store[id] = copy(val);
+ }
+ },
+ get: function(id) {
+ var values;
+ if (id != null && store[id]) {
+ values = store[id];
+ } else {
+ values = copy(catchall);
+ }
+ includeReadOnlyValues(id, values);
+ return copy(values);
+ },
+ addReadOnly: function(id, values) {
+ if (qq.isObject(store)) {
+ if (id === null) {
+ if (qq.isFunction(values)) {
+ readOnlyValues = values;
+ } else {
+ readOnlyValues = readOnlyValues || {};
+ qq.extend(readOnlyValues, values);
+ }
+ } else {
+ perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};
+ qq.extend(perIdReadOnlyValues[id], values);
+ }
+ }
+ },
+ remove: function(fileId) {
+ return delete store[fileId];
+ },
+ reset: function() {
+ store = {};
+ perIdReadOnlyValues = {};
+ catchall = initialValue;
+ }
+ };
+ },
+ _createUploadDataTracker: function() {
+ var self = this;
+ return new qq.UploadData({
+ getName: function(id) {
+ return self.getName(id);
+ },
+ getUuid: function(id) {
+ return self.getUuid(id);
+ },
+ getSize: function(id) {
+ return self.getSize(id);
+ },
+ onStatusChange: function(id, oldStatus, newStatus) {
+ self._onUploadStatusChange(id, oldStatus, newStatus);
+ self._options.callbacks.onStatusChange(id, oldStatus, newStatus);
+ self._maybeAllComplete(id, newStatus);
+ if (self._totalProgress) {
+ setTimeout(function() {
+ self._totalProgress.onStatusChange(id, oldStatus, newStatus);
+ }, 0);
+ }
+ }
+ });
+ },
+ _createUploadButton: function(spec) {
+ var self = this, acceptFiles = spec.accept || this._options.validation.acceptFiles, allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions, button;
+ function allowMultiple() {
+ if (qq.supportedFeatures.ajaxUploading) {
+ if (self._options.workarounds.iosEmptyVideos && qq.ios() && !qq.ios6() && self._isAllowedExtension(allowedExtensions, ".mov")) {
+ return false;
+ }
+ if (spec.multiple === undefined) {
+ return self._options.multiple;
+ }
+ return spec.multiple;
+ }
+ return false;
+ }
+ button = new qq.UploadButton({
+ acceptFiles: acceptFiles,
+ element: spec.element,
+ focusClass: this._options.classes.buttonFocus,
+ folders: spec.folders,
+ hoverClass: this._options.classes.buttonHover,
+ ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,
+ multiple: allowMultiple(),
+ name: this._options.request.inputName,
+ onChange: function(input) {
+ self._onInputChange(input);
+ },
+ title: spec.title == null ? this._options.text.fileInputTitle : spec.title
+ });
+ this._disposeSupport.addDisposer(function() {
+ button.dispose();
+ });
+ self._buttons.push(button);
+ return button;
+ },
+ _createUploadHandler: function(additionalOptions, namespace) {
+ var self = this, lastOnProgress = {}, options = {
+ debug: this._options.debug,
+ maxConnections: this._options.maxConnections,
+ cors: this._options.cors,
+ paramsStore: this._paramsStore,
+ endpointStore: this._endpointStore,
+ chunking: this._options.chunking,
+ resume: this._options.resume,
+ blobs: this._options.blobs,
+ log: qq.bind(self.log, self),
+ preventRetryParam: this._options.retry.preventRetryResponseProperty,
+ onProgress: function(id, name, loaded, total) {
+ if (loaded < 0 || total < 0) {
+ return;
+ }
+ if (lastOnProgress[id]) {
+ if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ } else {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ lastOnProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onComplete: function(id, name, result, xhr) {
+ delete lastOnProgress[id];
+ var status = self.getUploads({
+ id: id
+ }).status, retVal;
+ if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {
+ return;
+ }
+ retVal = self._onComplete(id, name, result, xhr);
+ if (retVal instanceof qq.Promise) {
+ retVal.done(function() {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ });
+ } else {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ }
+ },
+ onCancel: function(id, name, cancelFinalizationEffort) {
+ var promise = new qq.Promise();
+ self._handleCheckedCallback({
+ name: "onCancel",
+ callback: qq.bind(self._options.callbacks.onCancel, self, id, name),
+ onFailure: promise.failure,
+ onSuccess: function() {
+ cancelFinalizationEffort.then(function() {
+ self._onCancel(id, name);
+ });
+ promise.success();
+ },
+ identifier: id
+ });
+ return promise;
+ },
+ onUploadPrep: qq.bind(this._onUploadPrep, this),
+ onUpload: function(id, name) {
+ self._onUpload(id, name);
+ self._options.callbacks.onUpload(id, name);
+ },
+ onUploadChunk: function(id, name, chunkData) {
+ self._onUploadChunk(id, chunkData);
+ self._options.callbacks.onUploadChunk(id, name, chunkData);
+ },
+ onUploadChunkSuccess: function(id, chunkData, result, xhr) {
+ self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);
+ },
+ onResume: function(id, name, chunkData) {
+ return self._options.callbacks.onResume(id, name, chunkData);
+ },
+ onAutoRetry: function(id, name, responseJSON, xhr) {
+ return self._onAutoRetry.apply(self, arguments);
+ },
+ onUuidChanged: function(id, newUuid) {
+ self.log("Server requested UUID change from '" + self.getUuid(id) + "' to '" + newUuid + "'");
+ self.setUuid(id, newUuid);
+ },
+ getName: qq.bind(self.getName, self),
+ getUuid: qq.bind(self.getUuid, self),
+ getSize: qq.bind(self.getSize, self),
+ setSize: qq.bind(self._setSize, self),
+ getDataByUuid: function(uuid) {
+ return self.getUploads({
+ uuid: uuid
+ });
+ },
+ isQueued: function(id) {
+ var status = self.getUploads({
+ id: id
+ }).status;
+ return status === qq.status.QUEUED || status === qq.status.SUBMITTED || status === qq.status.UPLOAD_RETRYING || status === qq.status.PAUSED;
+ },
+ getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,
+ getIdsInBatch: self._uploadData.getIdsInBatch
+ };
+ qq.each(this._options.request, function(prop, val) {
+ options[prop] = val;
+ });
+ options.customHeaders = this._customHeadersStore;
+ if (additionalOptions) {
+ qq.each(additionalOptions, function(key, val) {
+ options[key] = val;
+ });
+ }
+ return new qq.UploadHandlerController(options, namespace);
+ },
+ _fileOrBlobRejected: function(id) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.REJECTED);
+ },
+ _formatSize: function(bytes) {
+ if (bytes === 0) {
+ return bytes + this._options.text.sizeSymbols[0];
+ }
+ var i = -1;
+ do {
+ bytes = bytes / 1e3;
+ i++;
+ } while (bytes > 999);
+ return Math.max(bytes, .1).toFixed(1) + this._options.text.sizeSymbols[i];
+ },
+ _generateExtraButtonSpecs: function() {
+ var self = this;
+ this._extraButtonSpecs = {};
+ qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {
+ var multiple = extraButtonOptionEntry.multiple, validation = qq.extend({}, self._options.validation, true), extraButtonSpec = qq.extend({}, extraButtonOptionEntry);
+ if (multiple === undefined) {
+ multiple = self._options.multiple;
+ }
+ if (extraButtonSpec.validation) {
+ qq.extend(validation, extraButtonOptionEntry.validation, true);
+ }
+ qq.extend(extraButtonSpec, {
+ multiple: multiple,
+ validation: validation
+ }, true);
+ self._initExtraButton(extraButtonSpec);
+ });
+ },
+ _getButton: function(buttonId) {
+ var extraButtonsSpec = this._extraButtonSpecs[buttonId];
+ if (extraButtonsSpec) {
+ return extraButtonsSpec.element;
+ } else if (buttonId === this._defaultButtonId) {
+ return this._options.button;
+ }
+ },
+ _getButtonId: function(buttonOrFileInputOrFile) {
+ var inputs, fileInput, fileBlobOrInput = buttonOrFileInputOrFile;
+ if (fileBlobOrInput instanceof qq.BlobProxy) {
+ fileBlobOrInput = fileBlobOrInput.referenceBlob;
+ }
+ if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {
+ if (qq.isFile(fileBlobOrInput)) {
+ return fileBlobOrInput.qqButtonId;
+ } else if (fileBlobOrInput.tagName.toLowerCase() === "input" && fileBlobOrInput.type.toLowerCase() === "file") {
+ return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ inputs = fileBlobOrInput.getElementsByTagName("input");
+ qq.each(inputs, function(idx, input) {
+ if (input.getAttribute("type") === "file") {
+ fileInput = input;
+ return false;
+ }
+ });
+ if (fileInput) {
+ return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ }
+ },
+ _getNotFinished: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED, qq.status.SUBMITTING, qq.status.SUBMITTED, qq.status.PAUSED ]
+ }).length;
+ },
+ _getValidationBase: function(buttonId) {
+ var extraButtonSpec = this._extraButtonSpecs[buttonId];
+ return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;
+ },
+ _getValidationDescriptor: function(fileWrapper) {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return {
+ name: qq.getFilename(fileWrapper.file.referenceBlob),
+ size: fileWrapper.file.referenceBlob.size
+ };
+ }
+ return {
+ name: this.getUploads({
+ id: fileWrapper.id
+ }).name,
+ size: this.getUploads({
+ id: fileWrapper.id
+ }).size
+ };
+ },
+ _getValidationDescriptors: function(fileWrappers) {
+ var self = this, fileDescriptors = [];
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ fileDescriptors.push(self._getValidationDescriptor(fileWrapper));
+ });
+ return fileDescriptors;
+ },
+ _handleCameraAccess: function() {
+ if (this._options.camera.ios && qq.ios()) {
+ var acceptIosCamera = "image/*;capture=camera", button = this._options.camera.button, buttonId = button ? this._getButtonId(button) : this._defaultButtonId, optionRoot = this._options;
+ if (buttonId && buttonId !== this._defaultButtonId) {
+ optionRoot = this._extraButtonSpecs[buttonId];
+ }
+ optionRoot.multiple = false;
+ if (optionRoot.validation.acceptFiles === null) {
+ optionRoot.validation.acceptFiles = acceptIosCamera;
+ } else {
+ optionRoot.validation.acceptFiles += "," + acceptIosCamera;
+ }
+ qq.each(this._buttons, function(idx, button) {
+ if (button.getButtonId() === buttonId) {
+ button.setMultiple(optionRoot.multiple);
+ button.setAcceptFiles(optionRoot.acceptFiles);
+ return false;
+ }
+ });
+ }
+ },
+ _handleCheckedCallback: function(details) {
+ var self = this, callbackRetVal = details.callback();
+ if (qq.isGenericPromise(callbackRetVal)) {
+ this.log(details.name + " - waiting for " + details.name + " promise to be fulfilled for " + details.identifier);
+ return callbackRetVal.then(function(successParam) {
+ self.log(details.name + " promise success for " + details.identifier);
+ details.onSuccess(successParam);
+ }, function() {
+ if (details.onFailure) {
+ self.log(details.name + " promise failure for " + details.identifier);
+ details.onFailure();
+ } else {
+ self.log(details.name + " promise failure for " + details.identifier);
+ }
+ });
+ }
+ if (callbackRetVal !== false) {
+ details.onSuccess(callbackRetVal);
+ } else {
+ if (details.onFailure) {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Invoking failure callback.");
+ details.onFailure();
+ } else {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Will not proceed.");
+ }
+ }
+ return callbackRetVal;
+ },
+ _handleNewFile: function(file, batchId, newFileWrapperList) {
+ var self = this, uuid = qq.getUniqueId(), size = -1, name = qq.getFilename(file), actualFile = file.blob || file, handler = this._customNewFileHandler ? this._customNewFileHandler : qq.bind(self._handleNewFileGeneric, self);
+ if (!qq.isInput(actualFile) && actualFile.size >= 0) {
+ size = actualFile.size;
+ }
+ handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {
+ uploadData: self._uploadData,
+ paramsStore: self._paramsStore,
+ addFileToHandler: function(id, file) {
+ self._handler.add(id, file);
+ self._netUploadedOrQueued++;
+ self._trackButton(id);
+ }
+ });
+ },
+ _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {
+ var id = this._uploadData.addFile({
+ uuid: uuid,
+ name: name,
+ size: size,
+ batchId: batchId
+ });
+ this._handler.add(id, file);
+ this._trackButton(id);
+ this._netUploadedOrQueued++;
+ fileList.push({
+ id: id,
+ file: file
+ });
+ },
+ _handlePasteSuccess: function(blob, extSuppliedName) {
+ var extension = blob.type.split("/")[1], name = extSuppliedName;
+ if (name == null) {
+ name = this._options.paste.defaultName;
+ }
+ name += "." + extension;
+ this.addFiles({
+ name: name,
+ blob: blob
+ });
+ },
+ _initExtraButton: function(spec) {
+ var button = this._createUploadButton({
+ accept: spec.validation.acceptFiles,
+ allowedExtensions: spec.validation.allowedExtensions,
+ element: spec.element,
+ folders: spec.folders,
+ multiple: spec.multiple,
+ title: spec.fileInputTitle
+ });
+ this._extraButtonSpecs[button.getButtonId()] = spec;
+ },
+ _initFormSupportAndParams: function() {
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore = this._createStore(this._options.request.params, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this._options.request.endpoint = this._formSupport.newEndpoint;
+ }
+ } else {
+ this._paramsStore = this._createStore(this._options.request.params);
+ }
+ },
+ _isDeletePossible: function() {
+ if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {
+ return false;
+ }
+ if (this._options.cors.expected) {
+ if (qq.supportedFeatures.deleteFileCorsXhr) {
+ return true;
+ }
+ if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ },
+ _isAllowedExtension: function(allowed, fileName) {
+ var valid = false;
+ if (!allowed.length) {
+ return true;
+ }
+ qq.each(allowed, function(idx, allowedExt) {
+ if (qq.isString(allowedExt)) {
+ var extRegex = new RegExp("\\." + allowedExt + "$", "i");
+ if (fileName.match(extRegex) != null) {
+ valid = true;
+ return false;
+ }
+ }
+ });
+ return valid;
+ },
+ _itemError: function(code, maybeNameOrNames, item) {
+ var message = this._options.messages[code], allowedExtensions = [], names = [].concat(maybeNameOrNames), name = names[0], buttonId = this._getButtonId(item), validationBase = this._getValidationBase(buttonId), extensionsForMessage, placeholderMatch;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {
+ if (qq.isString(allowedExtension)) {
+ allowedExtensions.push(allowedExtension);
+ }
+ });
+ extensionsForMessage = allowedExtensions.join(", ").toLowerCase();
+ r("{file}", this._options.formatFileName(name));
+ r("{extensions}", extensionsForMessage);
+ r("{sizeLimit}", this._formatSize(validationBase.sizeLimit));
+ r("{minSizeLimit}", this._formatSize(validationBase.minSizeLimit));
+ placeholderMatch = message.match(/(\{\w+\})/g);
+ if (placeholderMatch !== null) {
+ qq.each(placeholderMatch, function(idx, placeholder) {
+ r(placeholder, names[idx]);
+ });
+ }
+ this._options.callbacks.onError(null, name, message, undefined);
+ return message;
+ },
+ _manualRetry: function(id, callback) {
+ if (this._onBeforeManualRetry(id)) {
+ this._netUploadedOrQueued++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ if (callback) {
+ callback(id);
+ } else {
+ this._handler.retry(id);
+ }
+ return true;
+ }
+ },
+ _maybeAllComplete: function(id, status) {
+ var self = this, notFinished = this._getNotFinished();
+ if (status === qq.status.UPLOAD_SUCCESSFUL) {
+ this._succeededSinceLastAllComplete.push(id);
+ } else if (status === qq.status.UPLOAD_FAILED) {
+ this._failedSinceLastAllComplete.push(id);
+ }
+ if (notFinished === 0 && (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {
+ setTimeout(function() {
+ self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);
+ }, 0);
+ }
+ },
+ _maybeHandleIos8SafariWorkaround: function() {
+ var self = this;
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ setTimeout(function() {
+ window.alert(self._options.messages.unsupportedBrowserIos8Safari);
+ }, 0);
+ throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);
+ }
+ },
+ _maybeParseAndSendUploadError: function(id, name, response, xhr) {
+ if (!response.success) {
+ if (xhr && xhr.status !== 200 && !response.error) {
+ this._options.callbacks.onError(id, name, "XHR returned response code " + xhr.status, xhr);
+ } else {
+ var errorReason = response.error ? response.error : this._options.text.defaultResponseError;
+ this._options.callbacks.onError(id, name, errorReason, xhr);
+ }
+ }
+ },
+ _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {
+ var self = this;
+ if (items.length > index) {
+ if (validItem || !this._options.validation.stopOnFirstInvalidFile) {
+ setTimeout(function() {
+ var validationDescriptor = self._getValidationDescriptor(items[index]), buttonId = self._getButtonId(items[index].file), button = self._getButton(buttonId);
+ self._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),
+ onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),
+ onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),
+ identifier: "Item '" + validationDescriptor.name + "', size: " + validationDescriptor.size
+ });
+ }, 0);
+ } else if (!validItem) {
+ for (;index < items.length; index++) {
+ self._fileOrBlobRejected(items[index].id);
+ }
+ }
+ }
+ },
+ _onAllComplete: function(successful, failed) {
+ this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);
+ this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ },
+ _onAutoRetry: function(id, name, responseJSON, xhr, callback) {
+ var self = this;
+ self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];
+ if (self._shouldAutoRetry(id, name, responseJSON)) {
+ var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1e3;
+ self._maybeParseAndSendUploadError.apply(self, arguments);
+ self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);
+ self._onBeforeAutoRetry(id, name);
+ self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ self._retryTimeouts[id] = setTimeout(function() {
+ self.log("Starting retry for " + name + "...");
+ if (callback) {
+ callback(id);
+ } else {
+ self._handler.retry(id);
+ }
+ }, retryWaitPeriod);
+ return true;
+ }
+ },
+ _onBeforeAutoRetry: function(id, name) {
+ this.log("Waiting " + this._options.retry.autoAttemptDelay + " seconds before retrying " + name + "...");
+ },
+ _onBeforeManualRetry: function(id) {
+ var itemLimit = this._currentItemLimit, fileName;
+ if (this._preventRetries[id]) {
+ this.log("Retries are forbidden for id " + id, "warn");
+ return false;
+ } else if (this._handler.isValid(id)) {
+ fileName = this.getName(id);
+ if (this._options.callbacks.onManualRetry(id, fileName) === false) {
+ return false;
+ }
+ if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {
+ this._itemError("retryFailTooManyItems");
+ return false;
+ }
+ this.log("Retrying upload for '" + fileName + "' (id: " + id + ")...");
+ return true;
+ } else {
+ this.log("'" + id + "' is not a valid file ID", "error");
+ return false;
+ }
+ },
+ _onCancel: function(id, name) {
+ this._netUploadedOrQueued--;
+ clearTimeout(this._retryTimeouts[id]);
+ var storedItemIndex = qq.indexOf(this._storedIds, id);
+ if (!this._options.autoUpload && storedItemIndex >= 0) {
+ this._storedIds.splice(storedItemIndex, 1);
+ }
+ this._uploadData.setStatus(id, qq.status.CANCELED);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ if (!result.success) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);
+ if (result[this._options.retry.preventRetryResponseProperty] === true) {
+ this._preventRetries[id] = true;
+ }
+ } else {
+ if (result.thumbnailUrl) {
+ this._thumbnailUrls[id] = result.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);
+ }
+ this._maybeParseAndSendUploadError(id, name, result, xhr);
+ return result.success ? true : false;
+ },
+ _onDelete: function(id) {
+ this._uploadData.setStatus(id, qq.status.DELETING);
+ },
+ _onDeleteComplete: function(id, xhrOrXdr, isError) {
+ var name = this.getName(id);
+ if (isError) {
+ this._uploadData.setStatus(id, qq.status.DELETE_FAILED);
+ this.log("Delete request for '" + name + "' has failed.", "error");
+ if (xhrOrXdr.withCredentials === undefined) {
+ this._options.callbacks.onError(id, name, "Delete request failed", xhrOrXdr);
+ } else {
+ this._options.callbacks.onError(id, name, "Delete request failed with response code " + xhrOrXdr.status, xhrOrXdr);
+ }
+ } else {
+ this._netUploadedOrQueued--;
+ this._netUploaded--;
+ this._handler.expunge(id);
+ this._uploadData.setStatus(id, qq.status.DELETED);
+ this.log("Delete request for '" + name + "' has succeeded.");
+ }
+ },
+ _onInputChange: function(input) {
+ var fileIndex;
+ if (qq.supportedFeatures.ajaxUploading) {
+ for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {
+ this._annotateWithButtonId(input.files[fileIndex], input);
+ }
+ this.addFiles(input.files);
+ } else if (input.value.length > 0) {
+ this.addFiles(input);
+ }
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);
+ },
+ _onSubmit: function(id, name) {},
+ _onSubmitCallbackSuccess: function(id, name) {
+ this._onSubmit.apply(this, arguments);
+ this._uploadData.setStatus(id, qq.status.SUBMITTED);
+ this._onSubmitted.apply(this, arguments);
+ if (this._options.autoUpload) {
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ this._uploadFile(id);
+ } else {
+ this._storeForLater(id);
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ }
+ },
+ _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {
+ var uuid = this.getUuid(id), adjustedOnSuccessCallback;
+ if (onSuccessCallback) {
+ adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);
+ }
+ if (this._isDeletePossible()) {
+ this._handleCheckedCallback({
+ name: "onSubmitDelete",
+ callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),
+ onSuccess: adjustedOnSuccessCallback || qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),
+ identifier: id
+ });
+ return true;
+ } else {
+ this.log("Delete request ignored for ID " + id + ", delete feature is disabled or request not possible " + "due to CORS on a user agent that does not support pre-flighting.", "warn");
+ return false;
+ }
+ },
+ _onSubmitted: function(id) {},
+ _onTotalProgress: function(loaded, total) {
+ this._options.callbacks.onTotalProgress(loaded, total);
+ },
+ _onUploadPrep: function(id) {},
+ _onUpload: function(id, name) {
+ this._uploadData.setStatus(id, qq.status.UPLOADING);
+ },
+ _onUploadChunk: function(id, chunkData) {},
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.PAUSED) {
+ clearTimeout(this._retryTimeouts[id]);
+ }
+ },
+ _onValidateBatchCallbackFailure: function(fileWrappers) {
+ var self = this;
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ self._fileOrBlobRejected(fileWrapper.id);
+ });
+ },
+ _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {
+ var errorMessage, itemLimit = this._currentItemLimit, proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;
+ if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {
+ if (items.length > 0) {
+ this._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),
+ onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),
+ onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),
+ identifier: "Item '" + items[0].file.name + "', size: " + items[0].file.size
+ });
+ } else {
+ this._itemError("noFilesError");
+ }
+ } else {
+ this._onValidateBatchCallbackFailure(items);
+ errorMessage = this._options.messages.tooManyItemsError.replace(/\{netItems\}/g, proposedNetFilesUploadedOrQueued).replace(/\{itemLimit\}/g, itemLimit);
+ this._batchError(errorMessage);
+ }
+ },
+ _onValidateCallbackFailure: function(items, index, params, endpoint) {
+ var nextIndex = index + 1;
+ this._fileOrBlobRejected(items[index].id, items[index].file.name);
+ this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ },
+ _onValidateCallbackSuccess: function(items, index, params, endpoint) {
+ var self = this, nextIndex = index + 1, validationDescriptor = this._getValidationDescriptor(items[index]);
+ this._validateFileOrBlobData(items[index], validationDescriptor).then(function() {
+ self._upload(items[index].id, params, endpoint);
+ self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);
+ }, function() {
+ self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ });
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ if (items.length === 0) {
+ this._itemError("noFilesError");
+ return;
+ }
+ var validationDescriptors = this._getValidationDescriptors(items), buttonId = this._getButtonId(items[0].file), button = this._getButton(buttonId);
+ this._handleCheckedCallback({
+ name: "onValidateBatch",
+ callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),
+ onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),
+ onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),
+ identifier: "batch validation"
+ });
+ },
+ _preventLeaveInProgress: function() {
+ var self = this;
+ this._disposeSupport.attach(window, "beforeunload", function(e) {
+ if (self.getInProgress()) {
+ e = e || window.event;
+ e.returnValue = self._options.messages.onLeave;
+ return self._options.messages.onLeave;
+ }
+ });
+ },
+ _refreshSessionData: function() {
+ var self = this, options = this._options.session;
+ if (qq.Session && this._options.session.endpoint != null) {
+ if (!this._session) {
+ qq.extend(options, {
+ cors: this._options.cors
+ });
+ options.log = qq.bind(this.log, this);
+ options.addFileRecord = qq.bind(this._addCannedFile, this);
+ this._session = new qq.Session(options);
+ }
+ setTimeout(function() {
+ self._session.refresh().then(function(response, xhrOrXdr) {
+ self._sessionRequestComplete();
+ self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);
+ }, function(response, xhrOrXdr) {
+ self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);
+ });
+ }, 0);
+ }
+ },
+ _sessionRequestComplete: function() {},
+ _setSize: function(id, newSize) {
+ this._uploadData.updateSize(id, newSize);
+ this._totalProgress && this._totalProgress.onNewSize(id);
+ },
+ _shouldAutoRetry: function(id, name, responseJSON) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!this._preventRetries[id] && this._options.retry.enableAuto && uploadData.status !== qq.status.PAUSED) {
+ if (this._autoRetries[id] === undefined) {
+ this._autoRetries[id] = 0;
+ }
+ if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {
+ this._autoRetries[id] += 1;
+ return true;
+ }
+ }
+ return false;
+ },
+ _storeForLater: function(id) {
+ this._storedIds.push(id);
+ },
+ _trackButton: function(id) {
+ var buttonId;
+ if (qq.supportedFeatures.ajaxUploading) {
+ buttonId = this._handler.getFile(id).qqButtonId;
+ } else {
+ buttonId = this._getButtonId(this._handler.getInput(id));
+ }
+ if (buttonId) {
+ this._buttonIdsForFileIds[id] = buttonId;
+ }
+ },
+ _updateFormSupportAndParams: function(formElementOrId) {
+ this._options.form.element = formElementOrId;
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this.setEndpoint(this._formSupport.newEndpoint);
+ }
+ }
+ },
+ _upload: function(id, params, endpoint) {
+ var name = this.getName(id);
+ if (params) {
+ this.setParams(params, id);
+ }
+ if (endpoint) {
+ this.setEndpoint(endpoint, id);
+ }
+ this._handleCheckedCallback({
+ name: "onSubmit",
+ callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),
+ onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),
+ onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),
+ identifier: id
+ });
+ },
+ _uploadFile: function(id) {
+ if (!this._handler.upload(id)) {
+ this._uploadData.setStatus(id, qq.status.QUEUED);
+ }
+ },
+ _uploadStoredFiles: function() {
+ var idToUpload, stillSubmitting, self = this;
+ while (this._storedIds.length) {
+ idToUpload = this._storedIds.shift();
+ this._uploadFile(idToUpload);
+ }
+ stillSubmitting = this.getUploads({
+ status: qq.status.SUBMITTING
+ }).length;
+ if (stillSubmitting) {
+ qq.log("Still waiting for " + stillSubmitting + " files to clear submit queue. Will re-parse stored IDs array shortly.");
+ setTimeout(function() {
+ self._uploadStoredFiles();
+ }, 1e3);
+ }
+ },
+ _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {
+ var self = this, file = function() {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return fileWrapper.file.referenceBlob;
+ }
+ return fileWrapper.file;
+ }(), name = validationDescriptor.name, size = validationDescriptor.size, buttonId = this._getButtonId(fileWrapper.file), validationBase = this._getValidationBase(buttonId), validityChecker = new qq.Promise();
+ validityChecker.then(function() {}, function() {
+ self._fileOrBlobRejected(fileWrapper.id, name);
+ });
+ if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {
+ this._itemError("typeError", name, file);
+ return validityChecker.failure();
+ }
+ if (!this._options.validation.allowEmpty && size === 0) {
+ this._itemError("emptyError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {
+ this._itemError("sizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && size < validationBase.minSizeLimit) {
+ this._itemError("minSizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {
+ new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(validityChecker.success, function(errorCode) {
+ self._itemError(errorCode + "ImageError", name, file);
+ validityChecker.failure();
+ });
+ } else {
+ validityChecker.success();
+ }
+ return validityChecker;
+ },
+ _wrapCallbacks: function() {
+ var self, safeCallback, prop;
+ self = this;
+ safeCallback = function(name, callback, args) {
+ var errorMsg;
+ try {
+ return callback.apply(self, args);
+ } catch (exception) {
+ errorMsg = exception.message || exception.toString();
+ self.log("Caught exception in '" + name + "' callback - " + errorMsg, "error");
+ }
+ };
+ for (prop in this._options.callbacks) {
+ (function() {
+ var callbackName, callbackFunc;
+ callbackName = prop;
+ callbackFunc = self._options.callbacks[callbackName];
+ self._options.callbacks[callbackName] = function() {
+ return safeCallback(callbackName, callbackFunc, arguments);
+ };
+ })();
+ }
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.FineUploaderBasic = function(o) {
+ var self = this;
+ this._options = {
+ debug: false,
+ button: null,
+ multiple: true,
+ maxConnections: 3,
+ disableCancelForFormUploads: false,
+ autoUpload: true,
+ request: {
+ customHeaders: {},
+ endpoint: "/server/upload",
+ filenameParam: "qqfilename",
+ forceMultipart: true,
+ inputName: "qqfile",
+ method: "POST",
+ params: {},
+ paramsInBody: true,
+ totalFileSizeName: "qqtotalfilesize",
+ uuidName: "qquuid"
+ },
+ validation: {
+ allowedExtensions: [],
+ sizeLimit: 0,
+ minSizeLimit: 0,
+ itemLimit: 0,
+ stopOnFirstInvalidFile: true,
+ acceptFiles: null,
+ image: {
+ maxHeight: 0,
+ maxWidth: 0,
+ minHeight: 0,
+ minWidth: 0
+ },
+ allowEmpty: false
+ },
+ callbacks: {
+ onSubmit: function(id, name) {},
+ onSubmitted: function(id, name) {},
+ onComplete: function(id, name, responseJSON, maybeXhr) {},
+ onAllComplete: function(successful, failed) {},
+ onCancel: function(id, name) {},
+ onUpload: function(id, name) {},
+ onUploadChunk: function(id, name, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onProgress: function(id, name, loaded, total) {},
+ onTotalProgress: function(loaded, total) {},
+ onError: function(id, name, reason, maybeXhrOrXdr) {},
+ onAutoRetry: function(id, name, attemptNumber) {},
+ onManualRetry: function(id, name) {},
+ onValidateBatch: function(fileOrBlobData) {},
+ onValidate: function(fileOrBlobData) {},
+ onSubmitDelete: function(id) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {},
+ onPasteReceived: function(blob) {},
+ onStatusChange: function(id, oldStatus, newStatus) {},
+ onSessionRequestComplete: function(response, success, xhrOrXdr) {}
+ },
+ messages: {
+ typeError: "{file} has an invalid extension. Valid extension(s): {extensions}.",
+ sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
+ minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
+ emptyError: "{file} is empty, please select files again without it.",
+ noFilesError: "No files to upload.",
+ tooManyItemsError: "Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.",
+ maxHeightImageError: "Image is too tall.",
+ maxWidthImageError: "Image is too wide.",
+ minHeightImageError: "Image is not tall enough.",
+ minWidthImageError: "Image is not wide enough.",
+ retryFailTooManyItems: "Retry failed - you have reached your file limit.",
+ onLeave: "The files are being uploaded, if you leave now the upload will be canceled.",
+ unsupportedBrowserIos8Safari: "Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues."
+ },
+ retry: {
+ enableAuto: false,
+ maxAutoAttempts: 3,
+ autoAttemptDelay: 5,
+ preventRetryResponseProperty: "preventRetry"
+ },
+ classes: {
+ buttonHover: "qq-upload-button-hover",
+ buttonFocus: "qq-upload-button-focus"
+ },
+ chunking: {
+ enabled: false,
+ concurrent: {
+ enabled: false
+ },
+ mandatory: false,
+ paramNames: {
+ partIndex: "qqpartindex",
+ partByteOffset: "qqpartbyteoffset",
+ chunkSize: "qqchunksize",
+ totalFileSize: "qqtotalfilesize",
+ totalParts: "qqtotalparts"
+ },
+ partSize: 2e6,
+ success: {
+ endpoint: null
+ }
+ },
+ resume: {
+ enabled: false,
+ recordsExpireIn: 7,
+ paramNames: {
+ resuming: "qqresume"
+ }
+ },
+ formatFileName: function(fileOrBlobName) {
+ return fileOrBlobName;
+ },
+ text: {
+ defaultResponseError: "Upload failure reason unknown",
+ fileInputTitle: "file input",
+ sizeSymbols: [ "kB", "MB", "GB", "TB", "PB", "EB" ]
+ },
+ deleteFile: {
+ enabled: false,
+ method: "DELETE",
+ endpoint: "/server/upload",
+ customHeaders: {},
+ params: {}
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false,
+ allowXdr: false
+ },
+ blobs: {
+ defaultName: "misc_data"
+ },
+ paste: {
+ targetElement: null,
+ defaultName: "pasted_image"
+ },
+ camera: {
+ ios: false,
+ button: null
+ },
+ extraButtons: [],
+ session: {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ refreshOnReset: true
+ },
+ form: {
+ element: "qq-form",
+ autoUpload: false,
+ interceptSubmit: true
+ },
+ scaling: {
+ customResizer: null,
+ sendOriginal: true,
+ orient: true,
+ defaultType: null,
+ defaultQuality: 80,
+ failureText: "Failed to scale",
+ includeExif: false,
+ sizes: []
+ },
+ workarounds: {
+ iosEmptyVideos: true,
+ ios8SafariUploads: true,
+ ios8BrowserCrash: false
+ }
+ };
+ qq.extend(this._options, o, true);
+ this._buttons = [];
+ this._extraButtonSpecs = {};
+ this._buttonIdsForFileIds = [];
+ this._wrapCallbacks();
+ this._disposeSupport = new qq.DisposeSupport();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData = this._createUploadDataTracker();
+ this._initFormSupportAndParams();
+ this._customHeadersStore = this._createStore(this._options.request.customHeaders);
+ this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);
+ this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);
+ this._endpointStore = this._createStore(this._options.request.endpoint);
+ this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);
+ this._handler = this._createUploadHandler();
+ this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();
+ if (this._options.button) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._options.button,
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._generateExtraButtonSpecs();
+ this._handleCameraAccess();
+ if (this._options.paste.targetElement) {
+ if (qq.PasteSupport) {
+ this._pasteHandler = this._createPasteHandler();
+ } else {
+ this.log("Paste support module not found", "error");
+ }
+ }
+ this._preventLeaveInProgress();
+ this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));
+ this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._scaler = qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this)) || {};
+ if (this._scaler.enabled) {
+ this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);
+ }
+ if (qq.TotalProgress && qq.supportedFeatures.progressBar) {
+ this._totalProgress = new qq.TotalProgress(qq.bind(this._onTotalProgress, this), function(id) {
+ var entry = self._uploadData.retrieve({
+ id: id
+ });
+ return entry && entry.size || 0;
+ });
+ }
+ this._currentItemLimit = this._options.validation.itemLimit;
+ };
+ qq.FineUploaderBasic.prototype = qq.basePublicApi;
+ qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);
+ })();
+ qq.AjaxRequester = function(o) {
+ "use strict";
+ var log, shouldParamsBeInQueryString, queue = [], requestData = {}, options = {
+ acceptHeader: null,
+ validMethods: [ "PATCH", "POST", "PUT" ],
+ method: "POST",
+ contentType: "application/x-www-form-urlencoded",
+ maxConnections: 3,
+ customHeaders: {},
+ endpointStore: {},
+ paramsStore: {},
+ mandatedParams: {},
+ allowXRequestedWithAndCacheControl: true,
+ successfulResponseCodes: {
+ DELETE: [ 200, 202, 204 ],
+ PATCH: [ 200, 201, 202, 203, 204 ],
+ POST: [ 200, 201, 202, 203, 204 ],
+ PUT: [ 200, 201, 202, 203, 204 ],
+ GET: [ 200 ]
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onSend: function(id) {},
+ onComplete: function(id, xhrOrXdr, isError) {},
+ onProgress: null
+ };
+ qq.extend(options, o);
+ log = options.log;
+ if (qq.indexOf(options.validMethods, options.method) < 0) {
+ throw new Error("'" + options.method + "' is not a supported method for this type of request!");
+ }
+ function isSimpleMethod() {
+ return qq.indexOf([ "GET", "POST", "HEAD" ], options.method) >= 0;
+ }
+ function containsNonSimpleHeaders(headers) {
+ var containsNonSimple = false;
+ qq.each(containsNonSimple, function(idx, header) {
+ if (qq.indexOf([ "Accept", "Accept-Language", "Content-Language", "Content-Type" ], header) < 0) {
+ containsNonSimple = true;
+ return false;
+ }
+ });
+ return containsNonSimple;
+ }
+ function isXdr(xhr) {
+ return options.cors.expected && xhr.withCredentials === undefined;
+ }
+ function getCorsAjaxTransport() {
+ var xhrOrXdr;
+ if (window.XMLHttpRequest || window.ActiveXObject) {
+ xhrOrXdr = qq.createXhrInstance();
+ if (xhrOrXdr.withCredentials === undefined) {
+ xhrOrXdr = new XDomainRequest();
+ xhrOrXdr.onload = function() {};
+ xhrOrXdr.onerror = function() {};
+ xhrOrXdr.ontimeout = function() {};
+ xhrOrXdr.onprogress = function() {};
+ }
+ }
+ return xhrOrXdr;
+ }
+ function getXhrOrXdr(id, suppliedXhr) {
+ var xhrOrXdr = requestData[id].xhr;
+ if (!xhrOrXdr) {
+ if (suppliedXhr) {
+ xhrOrXdr = suppliedXhr;
+ } else {
+ if (options.cors.expected) {
+ xhrOrXdr = getCorsAjaxTransport();
+ } else {
+ xhrOrXdr = qq.createXhrInstance();
+ }
+ }
+ requestData[id].xhr = xhrOrXdr;
+ }
+ return xhrOrXdr;
+ }
+ function dequeue(id) {
+ var i = qq.indexOf(queue, id), max = options.maxConnections, nextId;
+ delete requestData[id];
+ queue.splice(i, 1);
+ if (queue.length >= max && i < max) {
+ nextId = queue[max - 1];
+ sendRequest(nextId);
+ }
+ }
+ function onComplete(id, xdrError) {
+ var xhr = getXhrOrXdr(id), method = options.method, isError = xdrError === true;
+ dequeue(id);
+ if (isError) {
+ log(method + " request for " + id + " has failed", "error");
+ } else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {
+ isError = true;
+ log(method + " request for " + id + " has failed - response code " + xhr.status, "error");
+ }
+ options.onComplete(id, xhr, isError);
+ }
+ function getParams(id) {
+ var onDemandParams = requestData[id].additionalParams, mandatedParams = options.mandatedParams, params;
+ if (options.paramsStore.get) {
+ params = options.paramsStore.get(id);
+ }
+ if (onDemandParams) {
+ qq.each(onDemandParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ if (mandatedParams) {
+ qq.each(mandatedParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ return params;
+ }
+ function sendRequest(id, optXhr) {
+ var xhr = getXhrOrXdr(id, optXhr), method = options.method, params = getParams(id), payload = requestData[id].payload, url;
+ options.onSend(id);
+ url = createUrl(id, params, requestData[id].additionalQueryParams);
+ if (isXdr(xhr)) {
+ xhr.onload = getXdrLoadHandler(id);
+ xhr.onerror = getXdrErrorHandler(id);
+ } else {
+ xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);
+ }
+ registerForUploadProgress(id);
+ xhr.open(method, url, true);
+ if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {
+ xhr.withCredentials = true;
+ }
+ setHeaders(id);
+ log("Sending " + method + " request for " + id);
+ if (payload) {
+ xhr.send(payload);
+ } else if (shouldParamsBeInQueryString || !params) {
+ xhr.send();
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/x-www-form-urlencoded") >= 0) {
+ xhr.send(qq.obj2url(params, ""));
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/json") >= 0) {
+ xhr.send(JSON.stringify(params));
+ } else {
+ xhr.send(params);
+ }
+ return xhr;
+ }
+ function createUrl(id, params, additionalQueryParams) {
+ var endpoint = options.endpointStore.get(id), addToPath = requestData[id].addToPath;
+ if (addToPath != undefined) {
+ endpoint += "/" + addToPath;
+ }
+ if (shouldParamsBeInQueryString && params) {
+ endpoint = qq.obj2url(params, endpoint);
+ }
+ if (additionalQueryParams) {
+ endpoint = qq.obj2url(additionalQueryParams, endpoint);
+ }
+ return endpoint;
+ }
+ function getXhrReadyStateChangeHandler(id) {
+ return function() {
+ if (getXhrOrXdr(id).readyState === 4) {
+ onComplete(id);
+ }
+ };
+ }
+ function registerForUploadProgress(id) {
+ var onProgress = options.onProgress;
+ if (onProgress) {
+ getXhrOrXdr(id).upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ onProgress(id, e.loaded, e.total);
+ }
+ };
+ }
+ }
+ function getXdrLoadHandler(id) {
+ return function() {
+ onComplete(id);
+ };
+ }
+ function getXdrErrorHandler(id) {
+ return function() {
+ onComplete(id, true);
+ };
+ }
+ function setHeaders(id) {
+ var xhr = getXhrOrXdr(id), customHeaders = options.customHeaders, onDemandHeaders = requestData[id].additionalHeaders || {}, method = options.method, allHeaders = {};
+ if (!isXdr(xhr)) {
+ options.acceptHeader && xhr.setRequestHeader("Accept", options.acceptHeader);
+ if (options.allowXRequestedWithAndCacheControl) {
+ if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ xhr.setRequestHeader("Cache-Control", "no-cache");
+ }
+ }
+ if (options.contentType && (method === "POST" || method === "PUT")) {
+ xhr.setRequestHeader("Content-Type", options.contentType);
+ }
+ qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);
+ qq.extend(allHeaders, onDemandHeaders);
+ qq.each(allHeaders, function(name, val) {
+ xhr.setRequestHeader(name, val);
+ });
+ }
+ }
+ function isResponseSuccessful(responseCode) {
+ return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;
+ }
+ function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {
+ requestData[id] = {
+ addToPath: addToPath,
+ additionalParams: additionalParams,
+ additionalQueryParams: additionalQueryParams,
+ additionalHeaders: additionalHeaders,
+ payload: payload
+ };
+ var len = queue.push(id);
+ if (len <= options.maxConnections) {
+ return sendRequest(id, optXhr);
+ }
+ }
+ shouldParamsBeInQueryString = options.method === "GET" || options.method === "DELETE";
+ qq.extend(this, {
+ initTransport: function(id) {
+ var path, params, headers, payload, cacheBuster, additionalQueryParams;
+ return {
+ withPath: function(appendToPath) {
+ path = appendToPath;
+ return this;
+ },
+ withParams: function(additionalParams) {
+ params = additionalParams;
+ return this;
+ },
+ withQueryParams: function(_additionalQueryParams_) {
+ additionalQueryParams = _additionalQueryParams_;
+ return this;
+ },
+ withHeaders: function(additionalHeaders) {
+ headers = additionalHeaders;
+ return this;
+ },
+ withPayload: function(thePayload) {
+ payload = thePayload;
+ return this;
+ },
+ withCacheBuster: function() {
+ cacheBuster = true;
+ return this;
+ },
+ send: function(optXhr) {
+ if (cacheBuster && qq.indexOf([ "GET", "DELETE" ], options.method) >= 0) {
+ params.qqtimestamp = new Date().getTime();
+ }
+ return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);
+ }
+ };
+ },
+ canceled: function(id) {
+ dequeue(id);
+ }
+ });
+ };
+ qq.UploadHandler = function(spec) {
+ "use strict";
+ var proxy = spec.proxy, fileState = {}, onCancel = proxy.onCancel, getName = proxy.getName;
+ qq.extend(this, {
+ add: function(id, fileItem) {
+ fileState[id] = fileItem;
+ fileState[id].temp = {};
+ },
+ cancel: function(id) {
+ var self = this, cancelFinalizationEffort = new qq.Promise(), onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);
+ onCancelRetVal.then(function() {
+ if (self.isValid(id)) {
+ fileState[id].canceled = true;
+ self.expunge(id);
+ }
+ cancelFinalizationEffort.success();
+ });
+ },
+ expunge: function(id) {
+ delete fileState[id];
+ },
+ getThirdPartyFileId: function(id) {
+ return fileState[id].key;
+ },
+ isValid: function(id) {
+ return fileState[id] !== undefined;
+ },
+ reset: function() {
+ fileState = {};
+ },
+ _getFileState: function(id) {
+ return fileState[id];
+ },
+ _setThirdPartyFileId: function(id, thirdPartyFileId) {
+ fileState[id].key = thirdPartyFileId;
+ },
+ _wasCanceled: function(id) {
+ return !!fileState[id].canceled;
+ }
+ });
+ };
+ qq.UploadHandlerController = function(o, namespace) {
+ "use strict";
+ var controller = this, chunkingPossible = false, concurrentChunkingPossible = false, chunking, preventRetryResponse, log, handler, options = {
+ paramsStore: {},
+ maxConnections: 3,
+ chunking: {
+ enabled: false,
+ multiple: {
+ enabled: false
+ }
+ },
+ log: function(str, level) {},
+ onProgress: function(id, fileName, loaded, total) {},
+ onComplete: function(id, fileName, response, xhr) {},
+ onCancel: function(id, fileName) {},
+ onUploadPrep: function(id) {},
+ onUpload: function(id, fileName) {},
+ onUploadChunk: function(id, fileName, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, response, xhr) {},
+ onAutoRetry: function(id, fileName, response, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onUuidChanged: function(id, newUuid) {},
+ getName: function(id) {},
+ setSize: function(id, newSize) {},
+ isQueued: function(id) {},
+ getIdsInProxyGroup: function(id) {},
+ getIdsInBatch: function(id) {}
+ }, chunked = {
+ done: function(id, chunkIdx, response, xhr) {
+ var chunkData = handler._getChunkData(id, chunkIdx);
+ handler._getFileState(id).attemptingResume = false;
+ delete handler._getFileState(id).temp.chunkProgress[chunkIdx];
+ handler._getFileState(id).loaded += chunkData.size;
+ options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);
+ },
+ finalize: function(id) {
+ var size = options.getSize(id), name = options.getName(id);
+ log("All chunks have been uploaded for " + id + " - finalizing....");
+ handler.finalizeChunks(id).then(function(response, xhr) {
+ log("Finalize successful for " + id);
+ var normaizedResponse = upload.normalizeResponse(response, true);
+ options.onProgress(id, name, size, size);
+ handler._maybeDeletePersistedChunkData(id);
+ upload.cleanup(id, normaizedResponse, xhr);
+ }, function(response, xhr) {
+ var normaizedResponse = upload.normalizeResponse(response, false);
+ log("Problem finalizing chunks for file ID " + id + " - " + normaizedResponse.error, "error");
+ if (normaizedResponse.reset) {
+ chunked.reset(id);
+ }
+ if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {
+ upload.cleanup(id, normaizedResponse, xhr);
+ }
+ });
+ },
+ handleFailure: function(chunkIdx, id, response, xhr) {
+ var name = options.getName(id);
+ log("Chunked upload request failed for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var responseToReport = upload.normalizeResponse(response, false), inProgressIdx;
+ if (responseToReport.reset) {
+ chunked.reset(id);
+ } else {
+ inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);
+ if (inProgressIdx >= 0) {
+ handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);
+ handler._getFileState(id).chunking.remaining.unshift(chunkIdx);
+ }
+ }
+ if (!handler._getFileState(id).temp.ignoreFailure) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = true;
+ log(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));
+ qq.each(handler._getXhrs(id), function(ckid, ckXhr) {
+ log(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ", id, ckid, ckXhr.readyState));
+ ckXhr.abort();
+ ckXhr._cancelled = true;
+ });
+ handler.moveInProgressToRemaining(id);
+ connectionManager.free(id, true);
+ }
+ if (!options.onAutoRetry(id, name, responseToReport, xhr)) {
+ upload.cleanup(id, responseToReport, xhr);
+ }
+ }
+ },
+ hasMoreParts: function(id) {
+ return !!handler._getFileState(id).chunking.remaining.length;
+ },
+ nextPart: function(id) {
+ var nextIdx = handler._getFileState(id).chunking.remaining.shift();
+ if (nextIdx >= handler._getTotalChunks(id)) {
+ nextIdx = null;
+ }
+ return nextIdx;
+ },
+ reset: function(id) {
+ log("Server or callback has ordered chunking effort to be restarted on next attempt for item ID " + id, "error");
+ handler._maybeDeletePersistedChunkData(id);
+ handler.reevaluateChunking(id);
+ handler._getFileState(id).loaded = 0;
+ },
+ sendNext: function(id) {
+ var size = options.getSize(id), name = options.getName(id), chunkIdx = chunked.nextPart(id), chunkData = handler._getChunkData(id, chunkIdx), resuming = handler._getFileState(id).attemptingResume, inProgressChunks = handler._getFileState(id).chunking.inProgress || [];
+ if (handler._getFileState(id).loaded == null) {
+ handler._getFileState(id).loaded = 0;
+ }
+ if (resuming && options.onResume(id, name, chunkData) === false) {
+ chunked.reset(id);
+ chunkIdx = chunked.nextPart(id);
+ chunkData = handler._getChunkData(id, chunkIdx);
+ resuming = false;
+ }
+ if (chunkIdx == null && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else {
+ log(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.", id, chunkIdx, chunkData.start + 1, chunkData.end, size));
+ options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));
+ inProgressChunks.push(chunkIdx);
+ handler._getFileState(id).chunking.inProgress = inProgressChunks;
+ if (concurrentChunkingPossible) {
+ connectionManager.open(id, chunkIdx);
+ }
+ if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {
+ chunked.sendNext(id);
+ }
+ if (chunkData.blob.size === 0) {
+ log(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.", chunkIdx, id), "error");
+ chunked.handleFailure(chunkIdx, id, "File is no longer available", null);
+ } else {
+ handler.uploadChunk(id, chunkIdx, resuming).then(function success(response, xhr) {
+ log("Chunked upload request succeeded for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var inProgressChunks = handler._getFileState(id).chunking.inProgress || [], responseToReport = upload.normalizeResponse(response, true), inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);
+ log(qq.format("Chunk {} for file {} uploaded successfully.", chunkIdx, id));
+ chunked.done(id, chunkIdx, responseToReport, xhr);
+ if (inProgressChunkIdx >= 0) {
+ inProgressChunks.splice(inProgressChunkIdx, 1);
+ }
+ handler._maybePersistChunkedState(id);
+ if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else if (chunked.hasMoreParts(id)) {
+ chunked.sendNext(id);
+ } else {
+ log(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}", id, JSON.stringify(inProgressChunks)));
+ }
+ }, function failure(response, xhr) {
+ chunked.handleFailure(chunkIdx, id, response, xhr);
+ }).done(function() {
+ handler.clearXhr(id, chunkIdx);
+ });
+ }
+ }
+ }
+ }, connectionManager = {
+ _open: [],
+ _openChunks: {},
+ _waiting: [],
+ available: function() {
+ var max = options.maxConnections, openChunkEntriesCount = 0, openChunksCount = 0;
+ qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {
+ openChunkEntriesCount++;
+ openChunksCount += openChunkIndexes.length;
+ });
+ return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);
+ },
+ free: function(id, dontAllowNext) {
+ var allowNext = !dontAllowNext, waitingIndex = qq.indexOf(connectionManager._waiting, id), connectionsIndex = qq.indexOf(connectionManager._open, id), nextId;
+ delete connectionManager._openChunks[id];
+ if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {
+ log("Generated blob upload has ended for " + id + ", disposing generated blob.");
+ delete handler._getFileState(id).file;
+ }
+ if (waitingIndex >= 0) {
+ connectionManager._waiting.splice(waitingIndex, 1);
+ } else if (allowNext && connectionsIndex >= 0) {
+ connectionManager._open.splice(connectionsIndex, 1);
+ nextId = connectionManager._waiting.shift();
+ if (nextId >= 0) {
+ connectionManager._open.push(nextId);
+ upload.start(nextId);
+ }
+ }
+ },
+ getWaitingOrConnected: function() {
+ var waitingOrConnected = [];
+ qq.each(connectionManager._openChunks, function(fileId, chunks) {
+ if (chunks && chunks.length) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ qq.each(connectionManager._open, function(idx, fileId) {
+ if (!connectionManager._openChunks[fileId]) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);
+ return waitingOrConnected;
+ },
+ isUsingConnection: function(id) {
+ return qq.indexOf(connectionManager._open, id) >= 0;
+ },
+ open: function(id, chunkIdx) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.push(id);
+ }
+ if (connectionManager.available()) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.pop();
+ connectionManager._open.push(id);
+ } else {
+ (function() {
+ var openChunksEntry = connectionManager._openChunks[id] || [];
+ openChunksEntry.push(chunkIdx);
+ connectionManager._openChunks[id] = openChunksEntry;
+ })();
+ }
+ return true;
+ }
+ return false;
+ },
+ reset: function() {
+ connectionManager._waiting = [];
+ connectionManager._open = [];
+ }
+ }, simple = {
+ send: function(id, name) {
+ handler._getFileState(id).loaded = 0;
+ log("Sending simple upload request for " + id);
+ handler.uploadFile(id).then(function(response, optXhr) {
+ log("Simple upload request succeeded for " + id);
+ var responseToReport = upload.normalizeResponse(response, true), size = options.getSize(id);
+ options.onProgress(id, name, size, size);
+ upload.maybeNewUuid(id, responseToReport);
+ upload.cleanup(id, responseToReport, optXhr);
+ }, function(response, optXhr) {
+ log("Simple upload request failed for " + id);
+ var responseToReport = upload.normalizeResponse(response, false);
+ if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {
+ upload.cleanup(id, responseToReport, optXhr);
+ }
+ });
+ }
+ }, upload = {
+ cancel: function(id) {
+ log("Cancelling " + id);
+ options.paramsStore.remove(id);
+ connectionManager.free(id);
+ },
+ cleanup: function(id, response, optXhr) {
+ var name = options.getName(id);
+ options.onComplete(id, name, response, optXhr);
+ if (handler._getFileState(id)) {
+ handler._clearXhrs && handler._clearXhrs(id);
+ }
+ connectionManager.free(id);
+ },
+ getProxyOrBlob: function(id) {
+ return handler.getProxy && handler.getProxy(id) || handler.getFile && handler.getFile(id);
+ },
+ initHandler: function() {
+ var handlerType = namespace ? qq[namespace] : qq.traditional, handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? "Xhr" : "Form";
+ handler = new handlerType[handlerModuleSubtype + "UploadHandler"](options, {
+ getDataByUuid: options.getDataByUuid,
+ getName: options.getName,
+ getSize: options.getSize,
+ getUuid: options.getUuid,
+ log: log,
+ onCancel: options.onCancel,
+ onProgress: options.onProgress,
+ onUuidChanged: options.onUuidChanged
+ });
+ if (handler._removeExpiredChunkingRecords) {
+ handler._removeExpiredChunkingRecords();
+ }
+ },
+ isDeferredEligibleForUpload: function(id) {
+ return options.isQueued(id);
+ },
+ maybeDefer: function(id, blob) {
+ if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {
+ options.onUploadPrep(id);
+ log("Attempting to generate a blob on-demand for " + id);
+ blob.create().then(function(generatedBlob) {
+ log("Generated an on-demand blob for " + id);
+ handler.updateBlob(id, generatedBlob);
+ options.setSize(id, generatedBlob.size);
+ handler.reevaluateChunking(id);
+ upload.maybeSendDeferredFiles(id);
+ }, function(errorMessage) {
+ var errorResponse = {};
+ if (errorMessage) {
+ errorResponse.error = errorMessage;
+ }
+ log(qq.format("Failed to generate blob for ID {}. Error message: {}.", id, errorMessage), "error");
+ options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);
+ upload.maybeSendDeferredFiles(id);
+ connectionManager.free(id);
+ });
+ } else {
+ return upload.maybeSendDeferredFiles(id);
+ }
+ return false;
+ },
+ maybeSendDeferredFiles: function(id) {
+ var idsInGroup = options.getIdsInProxyGroup(id), uploadedThisId = false;
+ if (idsInGroup && idsInGroup.length) {
+ log("Maybe ready to upload proxy group file " + id);
+ qq.each(idsInGroup, function(idx, idInGroup) {
+ if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {
+ uploadedThisId = idInGroup === id;
+ upload.now(idInGroup);
+ } else if (upload.isDeferredEligibleForUpload(idInGroup)) {
+ return false;
+ }
+ });
+ } else {
+ uploadedThisId = true;
+ upload.now(id);
+ }
+ return uploadedThisId;
+ },
+ maybeNewUuid: function(id, response) {
+ if (response.newUuid !== undefined) {
+ options.onUuidChanged(id, response.newUuid);
+ }
+ },
+ normalizeResponse: function(originalResponse, successful) {
+ var response = originalResponse;
+ if (!qq.isObject(originalResponse)) {
+ response = {};
+ if (qq.isString(originalResponse) && !successful) {
+ response.error = originalResponse;
+ }
+ }
+ response.success = successful;
+ return response;
+ },
+ now: function(id) {
+ var name = options.getName(id);
+ if (!controller.isValid(id)) {
+ throw new qq.Error(id + " is not a valid file ID to upload!");
+ }
+ options.onUpload(id, name);
+ if (chunkingPossible && handler._shouldChunkThisFile(id)) {
+ chunked.sendNext(id);
+ } else {
+ simple.send(id, name);
+ }
+ },
+ start: function(id) {
+ var blobToUpload = upload.getProxyOrBlob(id);
+ if (blobToUpload) {
+ return upload.maybeDefer(id, blobToUpload);
+ } else {
+ upload.now(id);
+ return true;
+ }
+ }
+ };
+ qq.extend(this, {
+ add: function(id, file) {
+ handler.add.apply(this, arguments);
+ },
+ upload: function(id) {
+ if (connectionManager.open(id)) {
+ return upload.start(id);
+ }
+ return false;
+ },
+ retry: function(id) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = false;
+ }
+ if (connectionManager.isUsingConnection(id)) {
+ return upload.start(id);
+ } else {
+ return controller.upload(id);
+ }
+ },
+ cancel: function(id) {
+ var cancelRetVal = handler.cancel(id);
+ if (qq.isGenericPromise(cancelRetVal)) {
+ cancelRetVal.then(function() {
+ upload.cancel(id);
+ });
+ } else if (cancelRetVal !== false) {
+ upload.cancel(id);
+ }
+ },
+ cancelAll: function() {
+ var waitingOrConnected = connectionManager.getWaitingOrConnected(), i;
+ if (waitingOrConnected.length) {
+ for (i = waitingOrConnected.length - 1; i >= 0; i--) {
+ controller.cancel(waitingOrConnected[i]);
+ }
+ }
+ connectionManager.reset();
+ },
+ getFile: function(id) {
+ if (handler.getProxy && handler.getProxy(id)) {
+ return handler.getProxy(id).referenceBlob;
+ }
+ return handler.getFile && handler.getFile(id);
+ },
+ isProxied: function(id) {
+ return !!(handler.getProxy && handler.getProxy(id));
+ },
+ getInput: function(id) {
+ if (handler.getInput) {
+ return handler.getInput(id);
+ }
+ },
+ reset: function() {
+ log("Resetting upload handler");
+ controller.cancelAll();
+ connectionManager.reset();
+ handler.reset();
+ },
+ expunge: function(id) {
+ if (controller.isValid(id)) {
+ return handler.expunge(id);
+ }
+ },
+ isValid: function(id) {
+ return handler.isValid(id);
+ },
+ getResumableFilesData: function() {
+ if (handler.getResumableFilesData) {
+ return handler.getResumableFilesData();
+ }
+ return [];
+ },
+ getThirdPartyFileId: function(id) {
+ if (controller.isValid(id)) {
+ return handler.getThirdPartyFileId(id);
+ }
+ },
+ pause: function(id) {
+ if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {
+ connectionManager.free(id);
+ handler.moveInProgressToRemaining(id);
+ return true;
+ }
+ return false;
+ },
+ isResumable: function(id) {
+ return !!handler.isResumable && handler.isResumable(id);
+ }
+ });
+ qq.extend(options, o);
+ log = options.log;
+ chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;
+ concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;
+ preventRetryResponse = function() {
+ var response = {};
+ response[options.preventRetryParam] = true;
+ return response;
+ }();
+ upload.initHandler();
+ };
+ qq.WindowReceiveMessage = function(o) {
+ "use strict";
+ var options = {
+ log: function(message, level) {}
+ }, callbackWrapperDetachers = {};
+ qq.extend(options, o);
+ qq.extend(this, {
+ receiveMessage: function(id, callback) {
+ var onMessageCallbackWrapper = function(event) {
+ callback(event.data);
+ };
+ if (window.postMessage) {
+ callbackWrapperDetachers[id] = qq(window).attach("message", onMessageCallbackWrapper);
+ } else {
+ log("iframe message passing not supported in this browser!", "error");
+ }
+ },
+ stopReceivingMessages: function(id) {
+ if (window.postMessage) {
+ var detacher = callbackWrapperDetachers[id];
+ if (detacher) {
+ detacher();
+ }
+ }
+ }
+ });
+ };
+ qq.FormUploadHandler = function(spec) {
+ "use strict";
+ var options = spec.options, handler = this, proxy = spec.proxy, formHandlerInstanceId = qq.getUniqueId(), onloadCallbacks = {}, detachLoadEvents = {}, postMessageCallbackTimers = {}, isCors = options.isCors, inputName = options.inputName, getUuid = proxy.getUuid, log = proxy.log, corsMessageReceiver = new qq.WindowReceiveMessage({
+ log: log
+ });
+ function expungeFile(id) {
+ delete detachLoadEvents[id];
+ if (isCors) {
+ clearTimeout(postMessageCallbackTimers[id]);
+ delete postMessageCallbackTimers[id];
+ corsMessageReceiver.stopReceivingMessages(id);
+ }
+ var iframe = document.getElementById(handler._getIframeName(id));
+ if (iframe) {
+ iframe.setAttribute("src", "javascript:false;");
+ qq(iframe).remove();
+ }
+ }
+ function getFileIdForIframeName(iframeName) {
+ return iframeName.split("_")[0];
+ }
+ function initIframeForUpload(name) {
+ var iframe = qq.toElement("");
+ iframe.setAttribute("id", name);
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+ return iframe;
+ }
+ function registerPostMessageCallback(iframe, callback) {
+ var iframeName = iframe.id, fileId = getFileIdForIframeName(iframeName), uuid = getUuid(fileId);
+ onloadCallbacks[uuid] = callback;
+ detachLoadEvents[fileId] = qq(iframe).attach("load", function() {
+ if (handler.getInput(fileId)) {
+ log("Received iframe load event for CORS upload request (iframe name " + iframeName + ")");
+ postMessageCallbackTimers[iframeName] = setTimeout(function() {
+ var errorMessage = "No valid message received from loaded iframe for iframe name " + iframeName;
+ log(errorMessage, "error");
+ callback({
+ error: errorMessage
+ });
+ }, 1e3);
+ }
+ });
+ corsMessageReceiver.receiveMessage(iframeName, function(message) {
+ log("Received the following window message: '" + message + "'");
+ var fileId = getFileIdForIframeName(iframeName), response = handler._parseJsonResponse(message), uuid = response.uuid, onloadCallback;
+ if (uuid && onloadCallbacks[uuid]) {
+ log("Handling response for iframe name " + iframeName);
+ clearTimeout(postMessageCallbackTimers[iframeName]);
+ delete postMessageCallbackTimers[iframeName];
+ handler._detachLoadEvent(iframeName);
+ onloadCallback = onloadCallbacks[uuid];
+ delete onloadCallbacks[uuid];
+ corsMessageReceiver.stopReceivingMessages(iframeName);
+ onloadCallback(response);
+ } else if (!uuid) {
+ log("'" + message + "' does not contain a UUID - ignoring.");
+ }
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, fileInput) {
+ super_.add(id, {
+ input: fileInput
+ });
+ fileInput.setAttribute("name", inputName);
+ if (fileInput.parentNode) {
+ qq(fileInput).remove();
+ }
+ },
+ expunge: function(id) {
+ expungeFile(id);
+ super_.expunge(id);
+ },
+ isValid: function(id) {
+ return super_.isValid(id) && handler._getFileState(id).input !== undefined;
+ }
+ };
+ });
+ qq.extend(this, {
+ getInput: function(id) {
+ return handler._getFileState(id).input;
+ },
+ _attachLoadEvent: function(iframe, callback) {
+ var responseDescriptor;
+ if (isCors) {
+ registerPostMessageCallback(iframe, callback);
+ } else {
+ detachLoadEvents[iframe.id] = qq(iframe).attach("load", function() {
+ log("Received response for " + iframe.id);
+ if (!iframe.parentNode) {
+ return;
+ }
+ try {
+ if (iframe.contentDocument && iframe.contentDocument.body && iframe.contentDocument.body.innerHTML == "false") {
+ return;
+ }
+ } catch (error) {
+ log("Error when attempting to access iframe during handling of upload response (" + error.message + ")", "error");
+ responseDescriptor = {
+ success: false
+ };
+ }
+ callback(responseDescriptor);
+ });
+ }
+ },
+ _createIframe: function(id) {
+ var iframeName = handler._getIframeName(id);
+ return initIframeForUpload(iframeName);
+ },
+ _detachLoadEvent: function(id) {
+ if (detachLoadEvents[id] !== undefined) {
+ detachLoadEvents[id]();
+ delete detachLoadEvents[id];
+ }
+ },
+ _getIframeName: function(fileId) {
+ return fileId + "_" + formHandlerInstanceId;
+ },
+ _initFormForUpload: function(spec) {
+ var method = spec.method, endpoint = spec.endpoint, params = spec.params, paramsInBody = spec.paramsInBody, targetName = spec.targetName, form = qq.toElement(""), url = endpoint;
+ if (paramsInBody) {
+ qq.obj2Inputs(params, form);
+ } else {
+ url = qq.obj2url(params, endpoint);
+ }
+ form.setAttribute("action", url);
+ form.setAttribute("target", targetName);
+ form.style.display = "none";
+ document.body.appendChild(form);
+ return form;
+ },
+ _parseJsonResponse: function(innerHtmlOrMessage) {
+ var response = {};
+ try {
+ response = qq.parseJson(innerHtmlOrMessage);
+ } catch (error) {
+ log("Error when attempting to parse iframe upload response (" + error.message + ")", "error");
+ }
+ return response;
+ }
+ });
+ };
+ qq.XhrUploadHandler = function(spec) {
+ "use strict";
+ var handler = this, namespace = spec.options.namespace, proxy = spec.proxy, chunking = spec.options.chunking, resume = spec.options.resume, chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking, resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume, getName = proxy.getName, getSize = proxy.getSize, getUuid = proxy.getUuid, getEndpoint = proxy.getEndpoint, getDataByUuid = proxy.getDataByUuid, onUuidChanged = proxy.onUuidChanged, onProgress = proxy.onProgress, log = proxy.log;
+ function abort(id) {
+ qq.each(handler._getXhrs(id), function(xhrId, xhr) {
+ var ajaxRequester = handler._getAjaxRequester(id, xhrId);
+ xhr.onreadystatechange = null;
+ xhr.upload.onprogress = null;
+ xhr.abort();
+ ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, blobOrProxy) {
+ if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {
+ super_.add(id, {
+ file: blobOrProxy
+ });
+ } else if (blobOrProxy instanceof qq.BlobProxy) {
+ super_.add(id, {
+ proxy: blobOrProxy
+ });
+ } else {
+ throw new Error("Passed obj is not a File, Blob, or proxy");
+ }
+ handler._initTempState(id);
+ resumeEnabled && handler._maybePrepareForResume(id);
+ },
+ expunge: function(id) {
+ abort(id);
+ handler._maybeDeletePersistedChunkData(id);
+ handler._clearXhrs(id);
+ super_.expunge(id);
+ }
+ };
+ });
+ qq.extend(this, {
+ clearCachedChunk: function(id, chunkIdx) {
+ delete handler._getFileState(id).temp.cachedChunks[chunkIdx];
+ },
+ clearXhr: function(id, chunkIdx) {
+ var tempState = handler._getFileState(id).temp;
+ if (tempState.xhrs) {
+ delete tempState.xhrs[chunkIdx];
+ }
+ if (tempState.ajaxRequesters) {
+ delete tempState.ajaxRequesters[chunkIdx];
+ }
+ },
+ finalizeChunks: function(id, responseParser) {
+ var lastChunkIdx = handler._getTotalChunks(id) - 1, xhr = handler._getXhr(id, lastChunkIdx);
+ if (responseParser) {
+ return new qq.Promise().success(responseParser(xhr), xhr);
+ }
+ return new qq.Promise().success({}, xhr);
+ },
+ getFile: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).file;
+ },
+ getProxy: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).proxy;
+ },
+ getResumableFilesData: function() {
+ var resumableFilesData = [];
+ handler._iterateResumeRecords(function(key, uploadData) {
+ handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);
+ var data = {
+ name: uploadData.name,
+ remaining: uploadData.chunking.remaining,
+ size: uploadData.size,
+ uuid: uploadData.uuid
+ };
+ if (uploadData.key) {
+ data.key = uploadData.key;
+ }
+ resumableFilesData.push(data);
+ });
+ return resumableFilesData;
+ },
+ isResumable: function(id) {
+ return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;
+ },
+ moveInProgressToRemaining: function(id, optInProgress, optRemaining) {
+ var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress, remaining = optRemaining || handler._getFileState(id).chunking.remaining;
+ if (inProgress) {
+ log(qq.format("Moving these chunks from in-progress {}, to remaining.", JSON.stringify(inProgress)));
+ inProgress.reverse();
+ qq.each(inProgress, function(idx, chunkIdx) {
+ remaining.unshift(chunkIdx);
+ });
+ inProgress.length = 0;
+ }
+ },
+ pause: function(id) {
+ if (handler.isValid(id)) {
+ log(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.", id, getName(id)));
+ handler._getFileState(id).paused = true;
+ abort(id);
+ return true;
+ }
+ },
+ reevaluateChunking: function(id) {
+ if (chunking && handler.isValid(id)) {
+ var state = handler._getFileState(id), totalChunks, i;
+ delete state.chunking;
+ state.chunking = {};
+ totalChunks = handler._getTotalChunks(id);
+ if (totalChunks > 1 || chunking.mandatory) {
+ state.chunking.enabled = true;
+ state.chunking.parts = totalChunks;
+ state.chunking.remaining = [];
+ for (i = 0; i < totalChunks; i++) {
+ state.chunking.remaining.push(i);
+ }
+ handler._initTempState(id);
+ } else {
+ state.chunking.enabled = false;
+ }
+ }
+ },
+ updateBlob: function(id, newBlob) {
+ if (handler.isValid(id)) {
+ handler._getFileState(id).file = newBlob;
+ }
+ },
+ _clearXhrs: function(id) {
+ var tempState = handler._getFileState(id).temp;
+ qq.each(tempState.ajaxRequesters, function(chunkId) {
+ delete tempState.ajaxRequesters[chunkId];
+ });
+ qq.each(tempState.xhrs, function(chunkId) {
+ delete tempState.xhrs[chunkId];
+ });
+ },
+ _createXhr: function(id, optChunkIdx) {
+ return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());
+ },
+ _getAjaxRequester: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];
+ },
+ _getChunkData: function(id, chunkIndex) {
+ var chunkSize = chunking.partSize, fileSize = getSize(id), fileOrBlob = handler.getFile(id), startBytes = chunkSize * chunkIndex, endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize, totalChunks = handler._getTotalChunks(id), cachedChunks = this._getFileState(id).temp.cachedChunks, blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);
+ cachedChunks[chunkIndex] = blob;
+ return {
+ part: chunkIndex,
+ start: startBytes,
+ end: endBytes,
+ count: totalChunks,
+ blob: blob,
+ size: endBytes - startBytes
+ };
+ },
+ _getChunkDataForCallback: function(chunkData) {
+ return {
+ partIndex: chunkData.part,
+ startByte: chunkData.start + 1,
+ endByte: chunkData.end,
+ totalParts: chunkData.count
+ };
+ },
+ _getLocalStorageId: function(id) {
+ var formatVersion = "5.0", name = getName(id), size = getSize(id), chunkSize = chunking.partSize, endpoint = getEndpoint(id);
+ return qq.format("qq{}resume{}-{}-{}-{}-{}", namespace, formatVersion, name, size, chunkSize, endpoint);
+ },
+ _getMimeType: function(id) {
+ return handler.getFile(id).type;
+ },
+ _getPersistableData: function(id) {
+ return handler._getFileState(id).chunking;
+ },
+ _getTotalChunks: function(id) {
+ if (chunking) {
+ var fileSize = getSize(id), chunkSize = chunking.partSize;
+ return Math.ceil(fileSize / chunkSize);
+ }
+ },
+ _getXhr: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.xhrs[chunkIdx];
+ },
+ _getXhrs: function(id) {
+ return handler._getFileState(id).temp.xhrs;
+ },
+ _iterateResumeRecords: function(callback) {
+ if (resumeEnabled) {
+ qq.each(localStorage, function(key, item) {
+ if (key.indexOf(qq.format("qq{}resume", namespace)) === 0) {
+ var uploadData = JSON.parse(item);
+ callback(key, uploadData);
+ }
+ });
+ }
+ },
+ _initTempState: function(id) {
+ handler._getFileState(id).temp = {
+ ajaxRequesters: {},
+ chunkProgress: {},
+ xhrs: {},
+ cachedChunks: {}
+ };
+ },
+ _markNotResumable: function(id) {
+ handler._getFileState(id).notResumable = true;
+ },
+ _maybeDeletePersistedChunkData: function(id) {
+ var localStorageId;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ if (localStorageId && localStorage.getItem(localStorageId)) {
+ localStorage.removeItem(localStorageId);
+ return true;
+ }
+ }
+ return false;
+ },
+ _maybePrepareForResume: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && state.key === undefined) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = localStorage.getItem(localStorageId);
+ if (persistedData) {
+ persistedData = JSON.parse(persistedData);
+ if (getDataByUuid(persistedData.uuid)) {
+ handler._markNotResumable(id);
+ } else {
+ log(qq.format("Identified file with ID {} and name of {} as resumable.", id, getName(id)));
+ onUuidChanged(id, persistedData.uuid);
+ state.key = persistedData.key;
+ state.chunking = persistedData.chunking;
+ state.loaded = persistedData.loaded;
+ state.attemptingResume = true;
+ handler.moveInProgressToRemaining(id);
+ }
+ }
+ }
+ },
+ _maybePersistChunkedState: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = {
+ name: getName(id),
+ size: getSize(id),
+ uuid: getUuid(id),
+ key: state.key,
+ chunking: state.chunking,
+ loaded: state.loaded,
+ lastUpdated: Date.now()
+ };
+ try {
+ localStorage.setItem(localStorageId, JSON.stringify(persistedData));
+ } catch (error) {
+ log(qq.format("Unable to save resume data for '{}' due to error: '{}'.", id, error.toString()), "warn");
+ }
+ }
+ },
+ _registerProgressHandler: function(id, chunkIdx, chunkSize) {
+ var xhr = handler._getXhr(id, chunkIdx), name = getName(id), progressCalculator = {
+ simple: function(loaded, total) {
+ var fileSize = getSize(id);
+ if (loaded === total) {
+ onProgress(id, name, fileSize, fileSize);
+ } else {
+ onProgress(id, name, loaded >= fileSize ? fileSize - 1 : loaded, fileSize);
+ }
+ },
+ chunked: function(loaded, total) {
+ var chunkProgress = handler._getFileState(id).temp.chunkProgress, totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded, loadedForRequest = loaded, totalForRequest = total, totalFileSize = getSize(id), estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize), totalLoadedForFile = totalSuccessfullyLoadedForFile;
+ chunkProgress[chunkIdx] = estActualChunkLoaded;
+ qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {
+ totalLoadedForFile += chunkLoaded;
+ });
+ onProgress(id, name, totalLoadedForFile, totalFileSize);
+ }
+ };
+ xhr.upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ var type = chunkSize == null ? "simple" : "chunked";
+ progressCalculator[type](e.loaded, e.total);
+ }
+ };
+ },
+ _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {
+ var xhrsId = optChunkIdx == null ? -1 : optChunkIdx, tempState = handler._getFileState(id).temp;
+ tempState.xhrs = tempState.xhrs || {};
+ tempState.ajaxRequesters = tempState.ajaxRequesters || {};
+ tempState.xhrs[xhrsId] = xhr;
+ if (optAjaxRequester) {
+ tempState.ajaxRequesters[xhrsId] = optAjaxRequester;
+ }
+ return xhr;
+ },
+ _removeExpiredChunkingRecords: function() {
+ var expirationDays = resume.recordsExpireIn;
+ handler._iterateResumeRecords(function(key, uploadData) {
+ var expirationDate = new Date(uploadData.lastUpdated);
+ expirationDate.setDate(expirationDate.getDate() + expirationDays);
+ if (expirationDate.getTime() <= Date.now()) {
+ log("Removing expired resume record with key " + key);
+ localStorage.removeItem(key);
+ }
+ });
+ },
+ _shouldChunkThisFile: function(id) {
+ var state = handler._getFileState(id);
+ if (!state.chunking) {
+ handler.reevaluateChunking(id);
+ }
+ return state.chunking.enabled;
+ }
+ });
+ };
+ qq.DeleteFileAjaxRequester = function(o) {
+ "use strict";
+ var requester, options = {
+ method: "DELETE",
+ uuidParamName: "qquuid",
+ endpointStore: {},
+ maxConnections: 3,
+ customHeaders: function(id) {
+ return {};
+ },
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {}
+ };
+ qq.extend(options, o);
+ function getMandatedParams() {
+ if (options.method.toUpperCase() === "POST") {
+ return {
+ _method: "DELETE"
+ };
+ }
+ return {};
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "POST", "DELETE" ],
+ method: options.method,
+ endpointStore: options.endpointStore,
+ paramsStore: options.paramsStore,
+ mandatedParams: getMandatedParams(),
+ maxConnections: options.maxConnections,
+ customHeaders: function(id) {
+ return options.customHeaders.get(id);
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendDelete: function(id, uuid, additionalMandatedParams) {
+ var additionalOptions = additionalMandatedParams || {};
+ options.log("Submitting delete file request for " + id);
+ if (options.method === "DELETE") {
+ requester.initTransport(id).withPath(uuid).withParams(additionalOptions).send();
+ } else {
+ additionalOptions[options.uuidParamName] = uuid;
+ requester.initTransport(id).withParams(additionalOptions).send();
+ }
+ }
+ });
+ };
+ (function() {
+ function detectSubsampling(img) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, canvas = document.createElement("canvas"), ctx;
+ if (iw * ih > 1024 * 1024) {
+ canvas.width = canvas.height = 1;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, -iw + 1, 0);
+ return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+ } else {
+ return false;
+ }
+ }
+ function detectVerticalSquash(img, iw, ih) {
+ var canvas = document.createElement("canvas"), sy = 0, ey = ih, py = ih, ctx, data, alpha, ratio;
+ canvas.width = 1;
+ canvas.height = ih;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, 0, 0);
+ data = ctx.getImageData(0, 0, 1, ih).data;
+ while (py > sy) {
+ alpha = data[(py - 1) * 4 + 3];
+ if (alpha === 0) {
+ ey = py;
+ } else {
+ sy = py;
+ }
+ py = ey + sy >> 1;
+ }
+ ratio = py / ih;
+ return ratio === 0 ? 1 : ratio;
+ }
+ function renderImageToDataURL(img, blob, options, doSquash) {
+ var canvas = document.createElement("canvas"), mime = options.mime || "image/jpeg", promise = new qq.Promise();
+ renderImageToCanvas(img, blob, canvas, options, doSquash).then(function() {
+ promise.success(canvas.toDataURL(mime, options.quality || .8));
+ });
+ return promise;
+ }
+ function maybeCalculateDownsampledDimensions(spec) {
+ var maxPixels = 5241e3;
+ if (!qq.ios()) {
+ throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");
+ }
+ if (spec.origHeight * spec.origWidth > maxPixels) {
+ return {
+ newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),
+ newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))
+ };
+ }
+ }
+ function renderImageToCanvas(img, blob, canvas, options, doSquash) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, width = options.width, height = options.height, ctx = canvas.getContext("2d"), promise = new qq.Promise(), modifiedDimensions;
+ ctx.save();
+ if (options.resize) {
+ return renderImageToCanvasWithCustomResizer({
+ blob: blob,
+ canvas: canvas,
+ image: img,
+ imageHeight: ih,
+ imageWidth: iw,
+ orientation: options.orientation,
+ resize: options.resize,
+ targetHeight: height,
+ targetWidth: width
+ });
+ }
+ if (!qq.supportedFeatures.unlimitedScaledImageSize) {
+ modifiedDimensions = maybeCalculateDownsampledDimensions({
+ origWidth: width,
+ origHeight: height
+ });
+ if (modifiedDimensions) {
+ qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h", width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight), "warn");
+ width = modifiedDimensions.newWidth;
+ height = modifiedDimensions.newHeight;
+ }
+ }
+ transformCoordinate(canvas, width, height, options.orientation);
+ if (qq.ios()) {
+ (function() {
+ if (detectSubsampling(img)) {
+ iw /= 2;
+ ih /= 2;
+ }
+ var d = 1024, tmpCanvas = document.createElement("canvas"), vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1, dw = Math.ceil(d * width / iw), dh = Math.ceil(d * height / ih / vertSquashRatio), sy = 0, dy = 0, tmpCtx, sx, dx;
+ tmpCanvas.width = tmpCanvas.height = d;
+ tmpCtx = tmpCanvas.getContext("2d");
+ while (sy < ih) {
+ sx = 0;
+ dx = 0;
+ while (sx < iw) {
+ tmpCtx.clearRect(0, 0, d, d);
+ tmpCtx.drawImage(img, -sx, -sy);
+ ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);
+ sx += d;
+ dx += dw;
+ }
+ sy += d;
+ dy += dh;
+ }
+ ctx.restore();
+ tmpCanvas = tmpCtx = null;
+ })();
+ } else {
+ ctx.drawImage(img, 0, 0, width, height);
+ }
+ canvas.qqImageRendered && canvas.qqImageRendered();
+ promise.success();
+ return promise;
+ }
+ function renderImageToCanvasWithCustomResizer(resizeInfo) {
+ var blob = resizeInfo.blob, image = resizeInfo.image, imageHeight = resizeInfo.imageHeight, imageWidth = resizeInfo.imageWidth, orientation = resizeInfo.orientation, promise = new qq.Promise(), resize = resizeInfo.resize, sourceCanvas = document.createElement("canvas"), sourceCanvasContext = sourceCanvas.getContext("2d"), targetCanvas = resizeInfo.canvas, targetHeight = resizeInfo.targetHeight, targetWidth = resizeInfo.targetWidth;
+ transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);
+ targetCanvas.height = targetHeight;
+ targetCanvas.width = targetWidth;
+ sourceCanvasContext.drawImage(image, 0, 0);
+ resize({
+ blob: blob,
+ height: targetHeight,
+ image: image,
+ sourceCanvas: sourceCanvas,
+ targetCanvas: targetCanvas,
+ width: targetWidth
+ }).then(function success() {
+ targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();
+ promise.success();
+ }, promise.failure);
+ return promise;
+ }
+ function transformCoordinate(canvas, width, height, orientation) {
+ switch (orientation) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ canvas.width = height;
+ canvas.height = width;
+ break;
+
+ default:
+ canvas.width = width;
+ canvas.height = height;
+ }
+ var ctx = canvas.getContext("2d");
+ switch (orientation) {
+ case 2:
+ ctx.translate(width, 0);
+ ctx.scale(-1, 1);
+ break;
+
+ case 3:
+ ctx.translate(width, height);
+ ctx.rotate(Math.PI);
+ break;
+
+ case 4:
+ ctx.translate(0, height);
+ ctx.scale(1, -1);
+ break;
+
+ case 5:
+ ctx.rotate(.5 * Math.PI);
+ ctx.scale(1, -1);
+ break;
+
+ case 6:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(0, -height);
+ break;
+
+ case 7:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(width, -height);
+ ctx.scale(-1, 1);
+ break;
+
+ case 8:
+ ctx.rotate(-.5 * Math.PI);
+ ctx.translate(-width, 0);
+ break;
+
+ default:
+ break;
+ }
+ }
+ function MegaPixImage(srcImage, errorCallback) {
+ var self = this;
+ if (window.Blob && srcImage instanceof Blob) {
+ (function() {
+ var img = new Image(), URL = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (!URL) {
+ throw Error("No createObjectURL function found to create blob url");
+ }
+ img.src = URL.createObjectURL(srcImage);
+ self.blob = srcImage;
+ srcImage = img;
+ })();
+ }
+ if (!srcImage.naturalWidth && !srcImage.naturalHeight) {
+ srcImage.onload = function() {
+ var listeners = self.imageLoadListeners;
+ if (listeners) {
+ self.imageLoadListeners = null;
+ setTimeout(function() {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i]();
+ }
+ }, 0);
+ }
+ };
+ srcImage.onerror = errorCallback;
+ this.imageLoadListeners = [];
+ }
+ this.srcImage = srcImage;
+ }
+ MegaPixImage.prototype.render = function(target, options) {
+ options = options || {};
+ var self = this, imgWidth = this.srcImage.naturalWidth, imgHeight = this.srcImage.naturalHeight, width = options.width, height = options.height, maxWidth = options.maxWidth, maxHeight = options.maxHeight, doSquash = !this.blob || this.blob.type === "image/jpeg", tagName = target.tagName.toLowerCase(), opt;
+ if (this.imageLoadListeners) {
+ this.imageLoadListeners.push(function() {
+ self.render(target, options);
+ });
+ return;
+ }
+ if (width && !height) {
+ height = imgHeight * width / imgWidth << 0;
+ } else if (height && !width) {
+ width = imgWidth * height / imgHeight << 0;
+ } else {
+ width = imgWidth;
+ height = imgHeight;
+ }
+ if (maxWidth && width > maxWidth) {
+ width = maxWidth;
+ height = imgHeight * width / imgWidth << 0;
+ }
+ if (maxHeight && height > maxHeight) {
+ height = maxHeight;
+ width = imgWidth * height / imgHeight << 0;
+ }
+ opt = {
+ width: width,
+ height: height
+ }, qq.each(options, function(optionsKey, optionsValue) {
+ opt[optionsKey] = optionsValue;
+ });
+ if (tagName === "img") {
+ (function() {
+ var oldTargetSrc = target.src;
+ renderImageToDataURL(self.srcImage, self.blob, opt, doSquash).then(function(dataUri) {
+ target.src = dataUri;
+ oldTargetSrc === target.src && target.onload();
+ });
+ })();
+ } else if (tagName === "canvas") {
+ renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);
+ }
+ if (typeof this.onrender === "function") {
+ this.onrender(target);
+ }
+ };
+ qq.MegaPixImage = MegaPixImage;
+ })();
+ qq.ImageGenerator = function(log) {
+ "use strict";
+ function isImg(el) {
+ return el.tagName.toLowerCase() === "img";
+ }
+ function isCanvas(el) {
+ return el.tagName.toLowerCase() === "canvas";
+ }
+ function isImgCorsSupported() {
+ return new Image().crossOrigin !== undefined;
+ }
+ function isCanvasSupported() {
+ var canvas = document.createElement("canvas");
+ return canvas.getContext && canvas.getContext("2d");
+ }
+ function determineMimeOfFileName(nameWithPath) {
+ var pathSegments = nameWithPath.split("/"), name = pathSegments[pathSegments.length - 1].split("?")[0], extension = qq.getExtension(name);
+ extension = extension && extension.toLowerCase();
+ switch (extension) {
+ case "jpeg":
+ case "jpg":
+ return "image/jpeg";
+
+ case "png":
+ return "image/png";
+
+ case "bmp":
+ return "image/bmp";
+
+ case "gif":
+ return "image/gif";
+
+ case "tiff":
+ case "tif":
+ return "image/tiff";
+ }
+ }
+ function isCrossOrigin(url) {
+ var targetAnchor = document.createElement("a"), targetProtocol, targetHostname, targetPort;
+ targetAnchor.href = url;
+ targetProtocol = targetAnchor.protocol;
+ targetPort = targetAnchor.port;
+ targetHostname = targetAnchor.hostname;
+ if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {
+ return true;
+ }
+ if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {
+ return true;
+ }
+ if (targetPort !== window.location.port && !qq.ie()) {
+ return true;
+ }
+ return false;
+ }
+ function registerImgLoadListeners(img, promise) {
+ img.onload = function() {
+ img.onload = null;
+ img.onerror = null;
+ promise.success(img);
+ };
+ img.onerror = function() {
+ img.onload = null;
+ img.onerror = null;
+ log("Problem drawing thumbnail!", "error");
+ promise.failure(img, "Problem drawing thumbnail!");
+ };
+ }
+ function registerCanvasDrawImageListener(canvas, promise) {
+ canvas.qqImageRendered = function() {
+ promise.success(canvas);
+ };
+ }
+ function registerThumbnailRenderedListener(imgOrCanvas, promise) {
+ var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);
+ if (isImg(imgOrCanvas)) {
+ registerImgLoadListeners(imgOrCanvas, promise);
+ } else if (isCanvas(imgOrCanvas)) {
+ registerCanvasDrawImageListener(imgOrCanvas, promise);
+ } else {
+ promise.failure(imgOrCanvas);
+ log(qq.format("Element container of type {} is not supported!", imgOrCanvas.tagName), "error");
+ }
+ return registered;
+ }
+ function draw(fileOrBlob, container, options) {
+ var drawPreview = new qq.Promise(), identifier = new qq.Identify(fileOrBlob, log), maxSize = options.maxSize, orient = options.orient == null ? true : options.orient, megapixErrorHandler = function() {
+ container.onerror = null;
+ container.onload = null;
+ log("Could not render preview, file may be too large!", "error");
+ drawPreview.failure(container, "Browser cannot render image!");
+ };
+ identifier.isPreviewable().then(function(mime) {
+ var dummyExif = {
+ parse: function() {
+ return new qq.Promise().success();
+ }
+ }, exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif, mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);
+ if (registerThumbnailRenderedListener(container, drawPreview)) {
+ exif.parse().then(function(exif) {
+ var orientation = exif && exif.Orientation;
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ orientation: orientation,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ }, function(failureMsg) {
+ log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", failureMsg));
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ });
+ }
+ }, function() {
+ log("Not previewable");
+ drawPreview.failure(container, "Not previewable");
+ });
+ return drawPreview;
+ }
+ function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {
+ var tempImg = new Image(), tempImgRender = new qq.Promise();
+ registerThumbnailRenderedListener(tempImg, tempImgRender);
+ if (isCrossOrigin(url)) {
+ tempImg.crossOrigin = "anonymous";
+ }
+ tempImg.src = url;
+ tempImgRender.then(function rendered() {
+ registerThumbnailRenderedListener(canvasOrImg, draw);
+ var mpImg = new qq.MegaPixImage(tempImg);
+ mpImg.render(canvasOrImg, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: determineMimeOfFileName(url),
+ resize: customResizeFunction
+ });
+ }, draw.failure);
+ }
+ function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {
+ registerThumbnailRenderedListener(img, draw);
+ qq(img).css({
+ maxWidth: maxSize + "px",
+ maxHeight: maxSize + "px"
+ });
+ img.src = url;
+ }
+ function drawFromUrl(url, container, options) {
+ var draw = new qq.Promise(), scale = options.scale, maxSize = scale ? options.maxSize : null;
+ if (scale && isImg(container)) {
+ if (isCanvasSupported()) {
+ if (isCrossOrigin(url) && !isImgCorsSupported()) {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ } else {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ }
+ } else {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ }
+ } else if (isCanvas(container)) {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ } else if (registerThumbnailRenderedListener(container, draw)) {
+ container.src = url;
+ }
+ return draw;
+ }
+ qq.extend(this, {
+ generate: function(fileBlobOrUrl, container, options) {
+ if (qq.isString(fileBlobOrUrl)) {
+ log("Attempting to update thumbnail based on server response.");
+ return drawFromUrl(fileBlobOrUrl, container, options || {});
+ } else {
+ log("Attempting to draw client-side image preview.");
+ return draw(fileBlobOrUrl, container, options || {});
+ }
+ }
+ });
+ this._testing = {};
+ this._testing.isImg = isImg;
+ this._testing.isCanvas = isCanvas;
+ this._testing.isCrossOrigin = isCrossOrigin;
+ this._testing.determineMimeOfFileName = determineMimeOfFileName;
+ };
+ qq.Exif = function(fileOrBlob, log) {
+ "use strict";
+ var TAG_IDS = [ 274 ], TAG_INFO = {
+ 274: {
+ name: "Orientation",
+ bytes: 2
+ }
+ };
+ function parseLittleEndian(hex) {
+ var result = 0, pow = 0;
+ while (hex.length > 0) {
+ result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);
+ hex = hex.substring(2, hex.length);
+ pow += 8;
+ }
+ return result;
+ }
+ function seekToApp1(offset, promise) {
+ var theOffset = offset, thePromise = promise;
+ if (theOffset === undefined) {
+ theOffset = 2;
+ thePromise = new qq.Promise();
+ }
+ qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {
+ var match = /^ffe([0-9])/.exec(hex), segmentLength;
+ if (match) {
+ if (match[1] !== "1") {
+ segmentLength = parseInt(hex.slice(4, 8), 16);
+ seekToApp1(theOffset + segmentLength + 2, thePromise);
+ } else {
+ thePromise.success(theOffset);
+ }
+ } else {
+ thePromise.failure("No EXIF header to be found!");
+ }
+ });
+ return thePromise;
+ }
+ function getApp1Offset() {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {
+ if (hex.indexOf("ffd8") !== 0) {
+ promise.failure("Not a valid JPEG!");
+ } else {
+ seekToApp1().then(function(offset) {
+ promise.success(offset);
+ }, function(error) {
+ promise.failure(error);
+ });
+ }
+ });
+ return promise;
+ }
+ function isLittleEndian(app1Start) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {
+ promise.success(hex === "4949");
+ });
+ return promise;
+ }
+ function getDirEntryCount(app1Start, littleEndian) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {
+ if (littleEndian) {
+ return promise.success(parseLittleEndian(hex));
+ } else {
+ promise.success(parseInt(hex, 16));
+ }
+ });
+ return promise;
+ }
+ function getIfd(app1Start, dirEntries) {
+ var offset = app1Start + 20, bytes = dirEntries * 12;
+ return qq.readBlobToHex(fileOrBlob, offset, bytes);
+ }
+ function getDirEntries(ifdHex) {
+ var entries = [], offset = 0;
+ while (offset + 24 <= ifdHex.length) {
+ entries.push(ifdHex.slice(offset, offset + 24));
+ offset += 24;
+ }
+ return entries;
+ }
+ function getTagValues(littleEndian, dirEntries) {
+ var TAG_VAL_OFFSET = 16, tagsToFind = qq.extend([], TAG_IDS), vals = {};
+ qq.each(dirEntries, function(idx, entry) {
+ var idHex = entry.slice(0, 4), id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16), tagsToFindIdx = tagsToFind.indexOf(id), tagValHex, tagName, tagValLength;
+ if (tagsToFindIdx >= 0) {
+ tagName = TAG_INFO[id].name;
+ tagValLength = TAG_INFO[id].bytes;
+ tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + tagValLength * 2);
+ vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);
+ tagsToFind.splice(tagsToFindIdx, 1);
+ }
+ if (tagsToFind.length === 0) {
+ return false;
+ }
+ });
+ return vals;
+ }
+ qq.extend(this, {
+ parse: function() {
+ var parser = new qq.Promise(), onParseFailure = function(message) {
+ log(qq.format("EXIF header parse failed: '{}' ", message));
+ parser.failure(message);
+ };
+ getApp1Offset().then(function(app1Offset) {
+ log(qq.format("Moving forward with EXIF header parsing for '{}'", fileOrBlob.name === undefined ? "blob" : fileOrBlob.name));
+ isLittleEndian(app1Offset).then(function(littleEndian) {
+ log(qq.format("EXIF Byte order is {} endian", littleEndian ? "little" : "big"));
+ getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {
+ log(qq.format("Found {} APP1 directory entries", dirEntryCount));
+ getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {
+ var dirEntries = getDirEntries(ifdHex), tagValues = getTagValues(littleEndian, dirEntries);
+ log("Successfully parsed some EXIF tags");
+ parser.success(tagValues);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ return parser;
+ }
+ });
+ this._testing = {};
+ this._testing.parseLittleEndian = parseLittleEndian;
+ };
+ qq.Identify = function(fileOrBlob, log) {
+ "use strict";
+ function isIdentifiable(magicBytes, questionableBytes) {
+ var identifiable = false, magicBytesEntries = [].concat(magicBytes);
+ qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {
+ if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {
+ identifiable = true;
+ return false;
+ }
+ });
+ return identifiable;
+ }
+ qq.extend(this, {
+ isPreviewable: function() {
+ var self = this, identifier = new qq.Promise(), previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ log(qq.format("Attempting to determine if {} can be rendered in this browser", name));
+ log("First pass: check type attribute of blob object.");
+ if (this.isPreviewableSync()) {
+ log("Second pass: check for magic bytes in file header.");
+ qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {
+ qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {
+ if (isIdentifiable(bytes, hex)) {
+ if (mime !== "image/tiff" || qq.supportedFeatures.tiffPreviews) {
+ previewable = true;
+ identifier.success(mime);
+ }
+ return false;
+ }
+ });
+ log(qq.format("'{}' is {} able to be rendered in this browser", name, previewable ? "" : "NOT"));
+ if (!previewable) {
+ identifier.failure();
+ }
+ }, function() {
+ log("Error reading file w/ name '" + name + "'. Not able to be rendered in this browser.");
+ identifier.failure();
+ });
+ } else {
+ identifier.failure();
+ }
+ return identifier;
+ },
+ isPreviewableSync: function() {
+ var fileMime = fileOrBlob.type, isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0, previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ if (isRecognizedImage) {
+ if (fileMime === "image/tiff") {
+ previewable = qq.supportedFeatures.tiffPreviews;
+ } else {
+ previewable = true;
+ }
+ }
+ !previewable && log(name + " is not previewable in this browser per the blob's type attr");
+ return previewable;
+ }
+ });
+ };
+ qq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {
+ "image/jpeg": "ffd8ff",
+ "image/gif": "474946",
+ "image/png": "89504e",
+ "image/bmp": "424d",
+ "image/tiff": [ "49492a00", "4d4d002a" ]
+ };
+ qq.ImageValidation = function(blob, log) {
+ "use strict";
+ function hasNonZeroLimits(limits) {
+ var atLeastOne = false;
+ qq.each(limits, function(limit, value) {
+ if (value > 0) {
+ atLeastOne = true;
+ return false;
+ }
+ });
+ return atLeastOne;
+ }
+ function getWidthHeight() {
+ var sizeDetermination = new qq.Promise();
+ new qq.Identify(blob, log).isPreviewable().then(function() {
+ var image = new Image(), url = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (url) {
+ image.onerror = function() {
+ log("Cannot determine dimensions for image. May be too large.", "error");
+ sizeDetermination.failure();
+ };
+ image.onload = function() {
+ sizeDetermination.success({
+ width: this.width,
+ height: this.height
+ });
+ };
+ image.src = url.createObjectURL(blob);
+ } else {
+ log("No createObjectURL function available to generate image URL!", "error");
+ sizeDetermination.failure();
+ }
+ }, sizeDetermination.failure);
+ return sizeDetermination;
+ }
+ function getFailingLimit(limits, dimensions) {
+ var failingLimit;
+ qq.each(limits, function(limitName, limitValue) {
+ if (limitValue > 0) {
+ var limitMatcher = /(max|min)(Width|Height)/.exec(limitName), dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1), actualValue = dimensions[dimensionPropName];
+ switch (limitMatcher[1]) {
+ case "min":
+ if (actualValue < limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+
+ case "max":
+ if (actualValue > limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+ }
+ }
+ });
+ return failingLimit;
+ }
+ this.validate = function(limits) {
+ var validationEffort = new qq.Promise();
+ log("Attempting to validate image.");
+ if (hasNonZeroLimits(limits)) {
+ getWidthHeight().then(function(dimensions) {
+ var failingLimit = getFailingLimit(limits, dimensions);
+ if (failingLimit) {
+ validationEffort.failure(failingLimit);
+ } else {
+ validationEffort.success();
+ }
+ }, validationEffort.success);
+ } else {
+ validationEffort.success();
+ }
+ return validationEffort;
+ };
+ };
+ qq.Session = function(spec) {
+ "use strict";
+ var options = {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ cors: {},
+ addFileRecord: function(sessionData) {},
+ log: function(message, level) {}
+ };
+ qq.extend(options, spec, true);
+ function isJsonResponseValid(response) {
+ if (qq.isArray(response)) {
+ return true;
+ }
+ options.log("Session response is not an array.", "error");
+ }
+ function handleFileItems(fileItems, success, xhrOrXdr, promise) {
+ var someItemsIgnored = false;
+ success = success && isJsonResponseValid(fileItems);
+ if (success) {
+ qq.each(fileItems, function(idx, fileItem) {
+ if (fileItem.uuid == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid UUID - ignoring.", idx), "error");
+ } else if (fileItem.name == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid name - ignoring.", idx), "error");
+ } else {
+ try {
+ options.addFileRecord(fileItem);
+ return true;
+ } catch (err) {
+ someItemsIgnored = true;
+ options.log(err.message, "error");
+ }
+ }
+ return false;
+ });
+ }
+ promise[success && !someItemsIgnored ? "success" : "failure"](fileItems, xhrOrXdr);
+ }
+ this.refresh = function() {
+ var refreshEffort = new qq.Promise(), refreshCompleteCallback = function(response, success, xhrOrXdr) {
+ handleFileItems(response, success, xhrOrXdr, refreshEffort);
+ }, requesterOptions = qq.extend({}, options), requester = new qq.SessionAjaxRequester(qq.extend(requesterOptions, {
+ onComplete: refreshCompleteCallback
+ }));
+ requester.queryServer();
+ return refreshEffort;
+ };
+ };
+ qq.SessionAjaxRequester = function(spec) {
+ "use strict";
+ var requester, options = {
+ endpoint: null,
+ customHeaders: {},
+ params: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ onComplete: function(response, success, xhrOrXdr) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, spec);
+ function onComplete(id, xhrOrXdr, isError) {
+ var response = null;
+ if (xhrOrXdr.responseText != null) {
+ try {
+ response = qq.parseJson(xhrOrXdr.responseText);
+ } catch (err) {
+ options.log("Problem parsing session response: " + err.message, "error");
+ isError = true;
+ }
+ }
+ options.onComplete(response, !isError, xhrOrXdr);
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: onComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ queryServer: function() {
+ var params = qq.extend({}, options.params);
+ options.log("Session query request.");
+ requester.initTransport("sessionRefresh").withParams(params).withCacheBuster().send();
+ }
+ });
+ };
+ qq.Scaler = function(spec, log) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizer, includeOriginal = spec.sendOriginal, orient = spec.orient, defaultType = spec.defaultType, defaultQuality = spec.defaultQuality / 100, failedToScaleText = spec.failureText, includeExif = spec.includeExif, sizes = this._getSortedSizes(spec.sizes);
+ qq.extend(this, {
+ enabled: qq.supportedFeatures.scaling && sizes.length > 0,
+ getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {
+ var self = this, records = [], originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData, identifier = new qq.Identify(originalBlob, log);
+ if (identifier.isPreviewableSync()) {
+ qq.each(sizes, function(idx, sizeRecord) {
+ var outputType = self._determineOutputType({
+ defaultType: defaultType,
+ requestedType: sizeRecord.type,
+ refType: originalBlob.type
+ });
+ records.push({
+ uuid: qq.getUniqueId(),
+ name: self._getName(originalFileName, {
+ name: sizeRecord.name,
+ type: outputType,
+ refType: originalBlob.type
+ }),
+ blob: new qq.BlobProxy(originalBlob, qq.bind(self._generateScaledImage, self, {
+ customResizeFunction: customResizeFunction,
+ maxSize: sizeRecord.maxSize,
+ orient: orient,
+ type: outputType,
+ quality: defaultQuality,
+ failedText: failedToScaleText,
+ includeExif: includeExif,
+ log: log
+ }))
+ });
+ });
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: includeOriginal ? originalBlob : null
+ });
+ } else {
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: originalBlob
+ });
+ }
+ return records;
+ },
+ handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {
+ var self = this, buttonId = file.qqButtonId || file.blob && file.blob.qqButtonId, scaledIds = [], originalId = null, addFileToHandler = api.addFileToHandler, uploadData = api.uploadData, paramsStore = api.paramsStore, proxyGroupId = qq.getUniqueId();
+ qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {
+ var blobSize = record.size, id;
+ if (record.blob instanceof qq.BlobProxy) {
+ blobSize = -1;
+ }
+ id = uploadData.addFile({
+ uuid: record.uuid,
+ name: record.name,
+ size: blobSize,
+ batchId: batchId,
+ proxyGroupId: proxyGroupId
+ });
+ if (record.blob instanceof qq.BlobProxy) {
+ scaledIds.push(id);
+ } else {
+ originalId = id;
+ }
+ if (record.blob) {
+ addFileToHandler(id, record.blob);
+ fileList.push({
+ id: id,
+ file: record.blob
+ });
+ } else {
+ uploadData.setStatus(id, qq.status.REJECTED);
+ }
+ });
+ if (originalId !== null) {
+ qq.each(scaledIds, function(idx, scaledId) {
+ var params = {
+ qqparentuuid: uploadData.retrieve({
+ id: originalId
+ }).uuid,
+ qqparentsize: uploadData.retrieve({
+ id: originalId
+ }).size
+ };
+ params[uuidParamName] = uploadData.retrieve({
+ id: scaledId
+ }).uuid;
+ uploadData.setParentId(scaledId, originalId);
+ paramsStore.addReadOnly(scaledId, params);
+ });
+ if (scaledIds.length) {
+ (function() {
+ var param = {};
+ param[uuidParamName] = uploadData.retrieve({
+ id: originalId
+ }).uuid;
+ paramsStore.addReadOnly(originalId, param);
+ })();
+ }
+ }
+ }
+ });
+ };
+ qq.extend(qq.Scaler.prototype, {
+ scaleImage: function(id, specs, api) {
+ "use strict";
+ if (!qq.supportedFeatures.scaling) {
+ throw new qq.Error("Scaling is not supported in this browser!");
+ }
+ var scalingEffort = new qq.Promise(), log = api.log, file = api.getFile(id), uploadData = api.uploadData.retrieve({
+ id: id
+ }), name = uploadData && uploadData.name, uuid = uploadData && uploadData.uuid, scalingOptions = {
+ customResizer: specs.customResizer,
+ sendOriginal: false,
+ orient: specs.orient,
+ defaultType: specs.type || null,
+ defaultQuality: specs.quality,
+ failedToScaleText: "Unable to scale",
+ sizes: [ {
+ name: "",
+ maxSize: specs.maxSize
+ } ]
+ }, scaler = new qq.Scaler(scalingOptions, log);
+ if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {
+ scalingEffort.failure();
+ log("Could not generate requested scaled image for " + id + ". " + "Scaling is either not possible in this browser, or the file could not be located.", "error");
+ } else {
+ qq.bind(function() {
+ var record = scaler.getFileRecords(uuid, name, file)[0];
+ if (record && record.blob instanceof qq.BlobProxy) {
+ record.blob.create().then(scalingEffort.success, scalingEffort.failure);
+ } else {
+ log(id + " is not a scalable image!", "error");
+ scalingEffort.failure();
+ }
+ }, this)();
+ }
+ return scalingEffort;
+ },
+ _determineOutputType: function(spec) {
+ "use strict";
+ var requestedType = spec.requestedType, defaultType = spec.defaultType, referenceType = spec.refType;
+ if (!defaultType && !requestedType) {
+ if (referenceType !== "image/jpeg") {
+ return "image/png";
+ }
+ return referenceType;
+ }
+ if (!requestedType) {
+ return defaultType;
+ }
+ if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {
+ if (requestedType === "image/tiff") {
+ return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;
+ }
+ return requestedType;
+ }
+ return defaultType;
+ },
+ _getName: function(originalName, scaledVersionProperties) {
+ "use strict";
+ var startOfExt = originalName.lastIndexOf("."), versionType = scaledVersionProperties.type || "image/png", referenceType = scaledVersionProperties.refType, scaledName = "", scaledExt = qq.getExtension(originalName), nameAppendage = "";
+ if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {
+ nameAppendage = " (" + scaledVersionProperties.name + ")";
+ }
+ if (startOfExt >= 0) {
+ scaledName = originalName.substr(0, startOfExt);
+ if (referenceType !== versionType) {
+ scaledExt = versionType.split("/")[1];
+ }
+ scaledName += nameAppendage + "." + scaledExt;
+ } else {
+ scaledName = originalName + nameAppendage;
+ }
+ return scaledName;
+ },
+ _getSortedSizes: function(sizes) {
+ "use strict";
+ sizes = qq.extend([], sizes);
+ return sizes.sort(function(a, b) {
+ if (a.maxSize > b.maxSize) {
+ return 1;
+ }
+ if (a.maxSize < b.maxSize) {
+ return -1;
+ }
+ return 0;
+ });
+ },
+ _generateScaledImage: function(spec, sourceFile) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizeFunction, log = spec.log, maxSize = spec.maxSize, orient = spec.orient, type = spec.type, quality = spec.quality, failedText = spec.failedText, includeExif = spec.includeExif && sourceFile.type === "image/jpeg" && type === "image/jpeg", scalingEffort = new qq.Promise(), imageGenerator = new qq.ImageGenerator(log), canvas = document.createElement("canvas");
+ log("Attempting to generate scaled version for " + sourceFile.name);
+ imageGenerator.generate(sourceFile, canvas, {
+ maxSize: maxSize,
+ orient: orient,
+ customResizeFunction: customResizeFunction
+ }).then(function() {
+ var scaledImageDataUri = canvas.toDataURL(type, quality), signalSuccess = function() {
+ log("Success generating scaled version for " + sourceFile.name);
+ var blob = qq.dataUriToBlob(scaledImageDataUri);
+ scalingEffort.success(blob);
+ };
+ if (includeExif) {
+ self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {
+ scaledImageDataUri = scaledImageDataUriWithExif;
+ signalSuccess();
+ }, function() {
+ log("Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.", "error");
+ signalSuccess();
+ });
+ } else {
+ signalSuccess();
+ }
+ }, function() {
+ log("Failed attempt to generate scaled version for " + sourceFile.name, "error");
+ scalingEffort.failure(failedText);
+ });
+ return scalingEffort;
+ },
+ _insertExifHeader: function(originalImage, scaledImageDataUri, log) {
+ "use strict";
+ var reader = new FileReader(), insertionEffort = new qq.Promise(), originalImageDataUri = "";
+ reader.onload = function() {
+ originalImageDataUri = reader.result;
+ insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));
+ };
+ reader.onerror = function() {
+ log("Problem reading " + originalImage.name + " during attempt to transfer EXIF data to scaled version.", "error");
+ insertionEffort.failure();
+ };
+ reader.readAsDataURL(originalImage);
+ return insertionEffort;
+ },
+ _dataUriToBlob: function(dataUri) {
+ "use strict";
+ var byteString, mimeString, arrayBuffer, intArray;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return this._createBlob(arrayBuffer, mimeString);
+ },
+ _createBlob: function(data, mime) {
+ "use strict";
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }
+ });
+ qq.ExifRestorer = function() {
+ var ExifRestorer = {};
+ ExifRestorer.KEY_STR = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + "ghijklmnopqrstuv" + "wxyz0123456789+/" + "=";
+ ExifRestorer.encode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0;
+ do {
+ chr1 = input[i++];
+ chr2 = input[i++];
+ chr3 = input[i++];
+ enc1 = chr1 >> 2;
+ enc2 = (chr1 & 3) << 4 | chr2 >> 4;
+ enc3 = (chr2 & 15) << 2 | chr3 >> 6;
+ enc4 = chr3 & 63;
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+ output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4);
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return output;
+ };
+ ExifRestorer.restore = function(origFileBase64, resizedFileBase64) {
+ var expectedBase64Header = "data:image/jpeg;base64,";
+ if (!origFileBase64.match(expectedBase64Header)) {
+ return resizedFileBase64;
+ }
+ var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, ""));
+ var segments = this.slice2Segments(rawImage);
+ var image = this.exifManipulation(resizedFileBase64, segments);
+ return expectedBase64Header + this.encode64(image);
+ };
+ ExifRestorer.exifManipulation = function(resizedFileBase64, segments) {
+ var exifArray = this.getExifArray(segments), newImageArray = this.insertExif(resizedFileBase64, exifArray), aBuffer = new Uint8Array(newImageArray);
+ return aBuffer;
+ };
+ ExifRestorer.getExifArray = function(segments) {
+ var seg;
+ for (var x = 0; x < segments.length; x++) {
+ seg = segments[x];
+ if (seg[0] == 255 & seg[1] == 225) {
+ return seg;
+ }
+ }
+ return [];
+ };
+ ExifRestorer.insertExif = function(resizedFileBase64, exifArray) {
+ var imageData = resizedFileBase64.replace("data:image/jpeg;base64,", ""), buf = this.decode64(imageData), separatePoint = buf.indexOf(255, 3), mae = buf.slice(0, separatePoint), ato = buf.slice(separatePoint), array = mae;
+ array = array.concat(exifArray);
+ array = array.concat(ato);
+ return array;
+ };
+ ExifRestorer.slice2Segments = function(rawImageArray) {
+ var head = 0, segments = [];
+ while (1) {
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218) {
+ break;
+ }
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216) {
+ head += 2;
+ } else {
+ var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3], endPoint = head + length + 2, seg = rawImageArray.slice(head, endPoint);
+ segments.push(seg);
+ head = endPoint;
+ }
+ if (head > rawImageArray.length) {
+ break;
+ }
+ }
+ return segments;
+ };
+ ExifRestorer.decode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0, buf = [];
+ var base64test = /[^A-Za-z0-9\+\/\=]/g;
+ if (base64test.exec(input)) {
+ throw new Error("There were invalid base64 characters in the input text. " + "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");
+ }
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+ do {
+ enc1 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc2 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc3 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc4 = this.KEY_STR.indexOf(input.charAt(i++));
+ chr1 = enc1 << 2 | enc2 >> 4;
+ chr2 = (enc2 & 15) << 4 | enc3 >> 2;
+ chr3 = (enc3 & 3) << 6 | enc4;
+ buf.push(chr1);
+ if (enc3 != 64) {
+ buf.push(chr2);
+ }
+ if (enc4 != 64) {
+ buf.push(chr3);
+ }
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return buf;
+ };
+ return ExifRestorer;
+ }();
+ qq.TotalProgress = function(callback, getSize) {
+ "use strict";
+ var perFileProgress = {}, totalLoaded = 0, totalSize = 0, lastLoadedSent = -1, lastTotalSent = -1, callbackProxy = function(loaded, total) {
+ if (loaded !== lastLoadedSent || total !== lastTotalSent) {
+ callback(loaded, total);
+ }
+ lastLoadedSent = loaded;
+ lastTotalSent = total;
+ }, noRetryableFiles = function(failed, retryable) {
+ var none = true;
+ qq.each(failed, function(idx, failedId) {
+ if (qq.indexOf(retryable, failedId) >= 0) {
+ none = false;
+ return false;
+ }
+ });
+ return none;
+ }, onCancel = function(id) {
+ updateTotalProgress(id, -1, -1);
+ delete perFileProgress[id];
+ }, onAllComplete = function(successful, failed, retryable) {
+ if (failed.length === 0 || noRetryableFiles(failed, retryable)) {
+ callbackProxy(totalSize, totalSize);
+ this.reset();
+ }
+ }, onNew = function(id) {
+ var size = getSize(id);
+ if (size > 0) {
+ updateTotalProgress(id, 0, size);
+ perFileProgress[id] = {
+ loaded: 0,
+ total: size
+ };
+ }
+ }, updateTotalProgress = function(id, newLoaded, newTotal) {
+ var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0, oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;
+ if (newLoaded === -1 && newTotal === -1) {
+ totalLoaded -= oldLoaded;
+ totalSize -= oldTotal;
+ } else {
+ if (newLoaded) {
+ totalLoaded += newLoaded - oldLoaded;
+ }
+ if (newTotal) {
+ totalSize += newTotal - oldTotal;
+ }
+ }
+ callbackProxy(totalLoaded, totalSize);
+ };
+ qq.extend(this, {
+ onAllComplete: onAllComplete,
+ onStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {
+ onCancel(id);
+ } else if (newStatus === qq.status.SUBMITTING) {
+ onNew(id);
+ }
+ },
+ onIndividualProgress: function(id, loaded, total) {
+ updateTotalProgress(id, loaded, total);
+ perFileProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onNewSize: function(id) {
+ onNew(id);
+ },
+ reset: function() {
+ perFileProgress = {};
+ totalLoaded = 0;
+ totalSize = 0;
+ }
+ });
+ };
+ qq.PasteSupport = function(o) {
+ "use strict";
+ var options, detachPasteHandler;
+ options = {
+ targetElement: null,
+ callbacks: {
+ log: function(message, level) {},
+ pasteReceived: function(blob) {}
+ }
+ };
+ function isImage(item) {
+ return item.type && item.type.indexOf("image/") === 0;
+ }
+ function registerPasteHandler() {
+ detachPasteHandler = qq(options.targetElement).attach("paste", function(event) {
+ var clipboardData = event.clipboardData;
+ if (clipboardData) {
+ qq.each(clipboardData.items, function(idx, item) {
+ if (isImage(item)) {
+ var blob = item.getAsFile();
+ options.callbacks.pasteReceived(blob);
+ }
+ });
+ }
+ });
+ }
+ function unregisterPasteHandler() {
+ if (detachPasteHandler) {
+ detachPasteHandler();
+ }
+ }
+ qq.extend(options, o);
+ registerPasteHandler();
+ qq.extend(this, {
+ reset: function() {
+ unregisterPasteHandler();
+ }
+ });
+ };
+ qq.FormSupport = function(options, startUpload, log) {
+ "use strict";
+ var self = this, interceptSubmit = options.interceptSubmit, formEl = options.element, autoUpload = options.autoUpload;
+ qq.extend(this, {
+ newEndpoint: null,
+ newAutoUpload: autoUpload,
+ attachedToForm: false,
+ getFormInputsAsObject: function() {
+ if (formEl == null) {
+ return null;
+ }
+ return self._form2Obj(formEl);
+ }
+ });
+ function determineNewEndpoint(formEl) {
+ if (formEl.getAttribute("action")) {
+ self.newEndpoint = formEl.getAttribute("action");
+ }
+ }
+ function validateForm(formEl, nativeSubmit) {
+ if (formEl.checkValidity && !formEl.checkValidity()) {
+ log("Form did not pass validation checks - will not upload.", "error");
+ nativeSubmit();
+ } else {
+ return true;
+ }
+ }
+ function maybeUploadOnSubmit(formEl) {
+ var nativeSubmit = formEl.submit;
+ qq(formEl).attach("submit", function(event) {
+ event = event || window.event;
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
+ validateForm(formEl, nativeSubmit) && startUpload();
+ });
+ formEl.submit = function() {
+ validateForm(formEl, nativeSubmit) && startUpload();
+ };
+ }
+ function determineFormEl(formEl) {
+ if (formEl) {
+ if (qq.isString(formEl)) {
+ formEl = document.getElementById(formEl);
+ }
+ if (formEl) {
+ log("Attaching to form element.");
+ determineNewEndpoint(formEl);
+ interceptSubmit && maybeUploadOnSubmit(formEl);
+ }
+ }
+ return formEl;
+ }
+ formEl = determineFormEl(formEl);
+ this.attachedToForm = !!formEl;
+ };
+ qq.extend(qq.FormSupport.prototype, {
+ _form2Obj: function(form) {
+ "use strict";
+ var obj = {}, notIrrelevantType = function(type) {
+ var irrelevantTypes = [ "button", "image", "reset", "submit" ];
+ return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;
+ }, radioOrCheckbox = function(type) {
+ return qq.indexOf([ "checkbox", "radio" ], type.toLowerCase()) >= 0;
+ }, ignoreValue = function(el) {
+ if (radioOrCheckbox(el.type) && !el.checked) {
+ return true;
+ }
+ return el.disabled && el.type.toLowerCase() !== "hidden";
+ }, selectValue = function(select) {
+ var value = null;
+ qq.each(qq(select).children(), function(idx, child) {
+ if (child.tagName.toLowerCase() === "option" && child.selected) {
+ value = child.value;
+ return false;
+ }
+ });
+ return value;
+ };
+ qq.each(form.elements, function(idx, el) {
+ if ((qq.isInput(el, true) || el.tagName.toLowerCase() === "textarea") && notIrrelevantType(el.type) && !ignoreValue(el)) {
+ obj[el.name] = el.value;
+ } else if (el.tagName.toLowerCase() === "select" && !ignoreValue(el)) {
+ var value = selectValue(el);
+ if (value !== null) {
+ obj[el.name] = value;
+ }
+ }
+ });
+ return obj;
+ }
+ });
+ qq.azure = qq.azure || {};
+ qq.azure.util = qq.azure.util || function() {
+ "use strict";
+ return {
+ AZURE_PARAM_PREFIX: "x-ms-meta-",
+ _paramNameMatchesAzureParameter: function(name) {
+ switch (name) {
+ case "Cache-Control":
+ case "Content-Disposition":
+ case "Content-Encoding":
+ case "Content-MD5":
+ case "x-ms-blob-content-encoding":
+ case "x-ms-blob-content-disposition":
+ case "x-ms-blob-content-md5":
+ case "x-ms-blob-cache-control":
+ return true;
+
+ default:
+ return false;
+ }
+ },
+ _getPrefixedParamName: function(name) {
+ if (qq.azure.util._paramNameMatchesAzureParameter(name)) {
+ return name;
+ } else {
+ return qq.azure.util.AZURE_PARAM_PREFIX + name;
+ }
+ },
+ getParamsAsHeaders: function(params) {
+ var headers = {};
+ qq.each(params, function(name, val) {
+ var headerName = qq.azure.util._getPrefixedParamName(name), value = null;
+ if (qq.isFunction(val)) {
+ value = String(val());
+ } else if (qq.isObject(val)) {
+ qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));
+ } else {
+ value = String(val);
+ }
+ if (value !== null) {
+ if (qq.azure.util._paramNameMatchesAzureParameter(name)) {
+ headers[headerName] = value;
+ } else {
+ headers[headerName] = encodeURIComponent(value);
+ }
+ }
+ });
+ return headers;
+ },
+ parseAzureError: function(responseText, log) {
+ var domParser = new DOMParser(), responseDoc = domParser.parseFromString(responseText, "application/xml"), errorTag = responseDoc.getElementsByTagName("Error")[0], errorDetails = {}, codeTag, messageTag;
+ log("Received error response: " + responseText, "error");
+ if (errorTag) {
+ messageTag = errorTag.getElementsByTagName("Message")[0];
+ if (messageTag) {
+ errorDetails.message = messageTag.textContent;
+ }
+ codeTag = errorTag.getElementsByTagName("Code")[0];
+ if (codeTag) {
+ errorDetails.code = codeTag.textContent;
+ }
+ log("Parsed Azure error: " + JSON.stringify(errorDetails), "error");
+ return errorDetails;
+ }
+ }
+ };
+ }();
+ (function() {
+ "use strict";
+ qq.nonTraditionalBasePublicApi = {
+ setUploadSuccessParams: function(params, id) {
+ this._uploadSuccessParamsStore.set(params, id);
+ },
+ setUploadSuccessEndpoint: function(endpoint, id) {
+ this._uploadSuccessEndpointStore.set(endpoint, id);
+ }
+ };
+ qq.nonTraditionalBasePrivateApi = {
+ _onComplete: function(id, name, result, xhr) {
+ var success = result.success ? true : false, self = this, onCompleteArgs = arguments, successEndpoint = this._uploadSuccessEndpointStore.get(id), successCustomHeaders = this._options.uploadSuccess.customHeaders, successMethod = this._options.uploadSuccess.method, cors = this._options.cors, promise = new qq.Promise(), uploadSuccessParams = this._uploadSuccessParamsStore.get(id), fileParams = this._paramsStore.get(id), onSuccessFromServer = function(successRequestResult) {
+ delete self._failedSuccessRequestCallbacks[id];
+ qq.extend(result, successRequestResult);
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.success(successRequestResult);
+ }, onFailureFromServer = function(successRequestResult) {
+ var callback = submitSuccessRequest;
+ qq.extend(result, successRequestResult);
+ if (result && result.reset) {
+ callback = null;
+ }
+ if (!callback) {
+ delete self._failedSuccessRequestCallbacks[id];
+ } else {
+ self._failedSuccessRequestCallbacks[id] = callback;
+ }
+ if (!self._onAutoRetry(id, name, result, xhr, callback)) {
+ qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);
+ promise.failure(successRequestResult);
+ }
+ }, submitSuccessRequest, successAjaxRequester;
+ if (success && successEndpoint) {
+ successAjaxRequester = new qq.UploadSuccessAjaxRequester({
+ endpoint: successEndpoint,
+ method: successMethod,
+ customHeaders: successCustomHeaders,
+ cors: cors,
+ log: qq.bind(this.log, this)
+ });
+ qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);
+ fileParams && qq.extend(uploadSuccessParams, fileParams, true);
+ submitSuccessRequest = qq.bind(function() {
+ successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams).then(onSuccessFromServer, onFailureFromServer);
+ }, self);
+ submitSuccessRequest();
+ return promise;
+ }
+ return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);
+ },
+ _manualRetry: function(id) {
+ var successRequestCallback = this._failedSuccessRequestCallbacks[id];
+ return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.azure.FineUploaderBasic = function(o) {
+ if (!qq.supportedFeatures.ajaxUploading) {
+ throw new qq.Error("Uploading directly to Azure is not possible in this browser.");
+ }
+ var options = {
+ signature: {
+ endpoint: null,
+ customHeaders: {}
+ },
+ blobProperties: {
+ name: "uuid"
+ },
+ uploadSuccess: {
+ endpoint: null,
+ method: "POST",
+ params: {},
+ customHeaders: {}
+ },
+ chunking: {
+ partSize: 4e6,
+ minFileSize: 4000001
+ }
+ };
+ qq.extend(options, o, true);
+ qq.FineUploaderBasic.call(this, options);
+ this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);
+ this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);
+ this._failedSuccessRequestCallbacks = {};
+ this._cannedBlobNames = {};
+ };
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);
+ qq.extend(qq.azure.FineUploaderBasic.prototype, {
+ getBlobName: function(id) {
+ if (this._cannedBlobNames[id] == null) {
+ return this._handler.getThirdPartyFileId(id);
+ }
+ return this._cannedBlobNames[id];
+ },
+ _getEndpointSpecificParams: function(id) {
+ return {
+ blob: this.getBlobName(id),
+ uuid: this.getUuid(id),
+ name: this.getName(id),
+ container: this._endpointStore.get(id)
+ };
+ },
+ _createUploadHandler: function() {
+ return qq.FineUploaderBasic.prototype._createUploadHandler.call(this, {
+ signature: this._options.signature,
+ onGetBlobName: qq.bind(this._determineBlobName, this),
+ deleteBlob: qq.bind(this._deleteBlob, this, true)
+ }, "azure");
+ },
+ _determineBlobName: function(id) {
+ var self = this, blobNameOptionValue = this._options.blobProperties.name, uuid = this.getUuid(id), filename = this.getName(id), fileExtension = qq.getExtension(filename), blobNameToUse = uuid;
+ if (qq.isString(blobNameOptionValue)) {
+ switch (blobNameOptionValue) {
+ case "uuid":
+ if (fileExtension !== undefined) {
+ blobNameToUse += "." + fileExtension;
+ }
+ return new qq.Promise().success(blobNameToUse);
+
+ case "filename":
+ return new qq.Promise().success(filename);
+
+ default:
+ return new qq.Promise.failure("Invalid blobName option value - " + blobNameOptionValue);
+ }
+ } else {
+ return blobNameOptionValue.call(this, id);
+ }
+ },
+ _addCannedFile: function(sessionData) {
+ var id;
+ if (sessionData.blobName == null) {
+ throw new qq.Error("Did not find blob name property in server session response. This is required!");
+ } else {
+ id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);
+ this._cannedBlobNames[id] = sessionData.blobName;
+ }
+ return id;
+ },
+ _deleteBlob: function(relatedToCancel, id) {
+ var self = this, deleteBlobSasUri = {}, blobUriStore = {
+ get: function(id) {
+ return self._endpointStore.get(id) + "/" + self.getBlobName(id);
+ }
+ }, deleteFileEndpointStore = {
+ get: function(id) {
+ return deleteBlobSasUri[id];
+ }
+ }, getSasSuccess = function(id, sasUri) {
+ deleteBlobSasUri[id] = sasUri;
+ deleteBlob.send(id);
+ }, getSasFailure = function(id, reason, xhr) {
+ if (relatedToCancel) {
+ self.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS", "error");
+ qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));
+ } else {
+ self._onDeleteComplete(id, xhr, true);
+ self._options.callbacks.onDeleteComplete(id, xhr, true);
+ }
+ }, deleteBlob = new qq.azure.DeleteBlob({
+ endpointStore: deleteFileEndpointStore,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ delete deleteBlobSasUri[id];
+ if (isError) {
+ if (relatedToCancel) {
+ self.log("Will cancel upload, but failed to remove uncommitted parts from Azure.", "error");
+ } else {
+ qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));
+ }
+ }
+ if (relatedToCancel) {
+ qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));
+ self.log("Deleted uncommitted blob chunks for " + id);
+ } else {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ }
+ }), getSas = new qq.azure.GetSas({
+ cors: this._options.cors,
+ customHeaders: this._options.signature.customHeaders,
+ endpointStore: {
+ get: function() {
+ return self._options.signature.endpoint;
+ }
+ },
+ restRequestVerb: deleteBlob.method,
+ log: qq.bind(self.log, self)
+ });
+ getSas.request(id, blobUriStore.get(id)).then(qq.bind(getSasSuccess, self, id), qq.bind(getSasFailure, self, id));
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return {
+ sendDelete: function(id, uuid) {
+ self._deleteBlob(false, id);
+ }
+ };
+ }
+ });
+ })();
+ qq.azure.XhrUploadHandler = function(spec, proxy) {
+ "use strict";
+ var handler = this, log = proxy.log, cors = spec.cors, endpointStore = spec.endpointStore, paramsStore = spec.paramsStore, signature = spec.signature, filenameParam = spec.filenameParam, minFileSizeForChunking = spec.chunking.minFileSize, deleteBlob = spec.deleteBlob, onGetBlobName = spec.onGetBlobName, getName = proxy.getName, getSize = proxy.getSize, getBlobMetadata = function(id) {
+ var params = paramsStore.get(id);
+ params[filenameParam] = getName(id);
+ return params;
+ }, api = {
+ putBlob: new qq.azure.PutBlob({
+ getBlobMetadata: getBlobMetadata,
+ log: log
+ }),
+ putBlock: new qq.azure.PutBlock({
+ log: log
+ }),
+ putBlockList: new qq.azure.PutBlockList({
+ getBlobMetadata: getBlobMetadata,
+ log: log
+ }),
+ getSasForPutBlobOrBlock: new qq.azure.GetSas({
+ cors: cors,
+ customHeaders: signature.customHeaders,
+ endpointStore: {
+ get: function() {
+ return signature.endpoint;
+ }
+ },
+ log: log,
+ restRequestVerb: "PUT"
+ })
+ };
+ function combineChunks(id) {
+ var promise = new qq.Promise();
+ getSignedUrl(id).then(function(sasUri) {
+ var mimeType = handler._getMimeType(id), blockIdEntries = handler._getPersistableData(id).blockIdEntries;
+ api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {
+ handler._registerXhr(id, null, xhr, api.putBlockList);
+ }).then(function(xhr) {
+ log("Success combining chunks for id " + id);
+ promise.success({}, xhr);
+ }, function(xhr) {
+ log("Attempt to combine chunks failed for id " + id, "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ }
+ function determineBlobUrl(id) {
+ var containerUrl = endpointStore.get(id), promise = new qq.Promise(), getBlobNameSuccess = function(blobName) {
+ handler._setThirdPartyFileId(id, blobName);
+ promise.success(containerUrl + "/" + blobName);
+ }, getBlobNameFailure = function(reason) {
+ promise.failure(reason);
+ };
+ onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);
+ return promise;
+ }
+ function getSignedUrl(id, optChunkIdx) {
+ var getSasId = optChunkIdx == null ? id : id + "." + optChunkIdx, promise = new qq.Promise(), getSasSuccess = function(sasUri) {
+ log("GET SAS request succeeded.");
+ promise.success(sasUri);
+ }, getSasFailure = function(reason, getSasXhr) {
+ log("GET SAS request failed: " + reason, "error");
+ promise.failure({
+ error: "Problem communicating with local server"
+ }, getSasXhr);
+ }, determineBlobUrlSuccess = function(blobUrl) {
+ api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(getSasSuccess, getSasFailure);
+ }, determineBlobUrlFailure = function(reason) {
+ log(qq.format("Failed to determine blob name for ID {} - {}", id, reason), "error");
+ promise.failure({
+ error: reason
+ });
+ };
+ determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);
+ return promise;
+ }
+ function handleFailure(xhr, promise) {
+ var azureError = qq.azure.util.parseAzureError(xhr.responseText, log), errorMsg = "Problem sending file to Azure";
+ promise.failure({
+ error: errorMsg,
+ azureError: azureError && azureError.message,
+ reset: xhr.status === 403
+ });
+ }
+ qq.extend(this, {
+ uploadChunk: function(id, chunkIdx) {
+ var promise = new qq.Promise();
+ getSignedUrl(id, chunkIdx).then(function(sasUri) {
+ var xhr = handler._createXhr(id, chunkIdx), chunkData = handler._getChunkData(id, chunkIdx);
+ handler._registerProgressHandler(id, chunkIdx, chunkData.size);
+ handler._registerXhr(id, chunkIdx, xhr, api.putBlock);
+ api.putBlock.upload(id + "." + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(function(blockIdEntry) {
+ if (!handler._getPersistableData(id).blockIdEntries) {
+ handler._getPersistableData(id).blockIdEntries = [];
+ }
+ handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);
+ log("Put Block call succeeded for " + id);
+ promise.success({}, xhr);
+ }, function() {
+ log(qq.format("Put Block call failed for ID {} on part {}", id, chunkIdx), "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ },
+ uploadFile: function(id) {
+ var promise = new qq.Promise(), fileOrBlob = handler.getFile(id);
+ getSignedUrl(id).then(function(sasUri) {
+ var xhr = handler._createXhr(id);
+ handler._registerProgressHandler(id);
+ api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(function() {
+ log("Put Blob call succeeded for " + id);
+ promise.success({}, xhr);
+ }, function() {
+ log("Put Blob call failed for " + id, "error");
+ handleFailure(xhr, promise);
+ });
+ }, promise.failure);
+ return promise;
+ }
+ });
+ qq.extend(this, new qq.XhrUploadHandler({
+ options: qq.extend({
+ namespace: "azure"
+ }, spec),
+ proxy: qq.extend({
+ getEndpoint: spec.endpointStore.get
+ }, proxy)
+ }));
+ qq.override(this, function(super_) {
+ return {
+ expunge: function(id) {
+ var relatedToCancel = handler._wasCanceled(id), chunkingData = handler._getPersistableData(id), blockIdEntries = chunkingData && chunkingData.blockIdEntries || [];
+ if (relatedToCancel && blockIdEntries.length > 0) {
+ deleteBlob(id);
+ }
+ super_.expunge(id);
+ },
+ finalizeChunks: function(id) {
+ return combineChunks(id);
+ },
+ _shouldChunkThisFile: function(id) {
+ var maybePossible = super_._shouldChunkThisFile(id);
+ return maybePossible && getSize(id) >= minFileSizeForChunking;
+ }
+ };
+ });
+ };
+ qq.azure.GetSas = function(o) {
+ "use strict";
+ var requester, options = {
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ customHeaders: {},
+ restRequestVerb: "PUT",
+ endpointStore: null,
+ log: function(str, level) {}
+ }, requestPromises = {};
+ qq.extend(options, o);
+ function sasResponseReceived(id, xhr, isError) {
+ var promise = requestPromises[id];
+ if (isError) {
+ promise.failure("Received response code " + xhr.status, xhr);
+ } else {
+ if (xhr.responseText.length) {
+ promise.success(xhr.responseText);
+ } else {
+ promise.failure("Empty response.", xhr);
+ }
+ }
+ delete requestPromises[id];
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ successfulResponseCodes: {
+ GET: [ 200 ]
+ },
+ contentType: null,
+ customHeaders: options.customHeaders,
+ endpointStore: options.endpointStore,
+ cors: options.cors,
+ log: options.log,
+ onComplete: sasResponseReceived
+ }));
+ qq.extend(this, {
+ request: function(id, blobUri) {
+ var requestPromise = new qq.Promise(), restVerb = options.restRequestVerb;
+ options.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.", restVerb, id));
+ requestPromises[id] = requestPromise;
+ requester.initTransport(id).withParams({
+ bloburi: blobUri,
+ _method: restVerb
+ }).withCacheBuster().send();
+ return requestPromise;
+ }
+ });
+ };
+ qq.UploadSuccessAjaxRequester = function(o) {
+ "use strict";
+ var requester, pendingRequests = [], options = {
+ method: "POST",
+ endpoint: null,
+ maxConnections: 3,
+ customHeaders: {},
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {}
+ };
+ qq.extend(options, o);
+ function handleSuccessResponse(id, xhrOrXdr, isError) {
+ var promise = pendingRequests[id], responseJson = xhrOrXdr.responseText, successIndicator = {
+ success: true
+ }, failureIndicator = {
+ success: false
+ }, parsedResponse;
+ delete pendingRequests[id];
+ options.log(qq.format("Received the following response body to an upload success request for id {}: {}", id, responseJson));
+ try {
+ parsedResponse = qq.parseJson(responseJson);
+ if (isError || parsedResponse && (parsedResponse.error || parsedResponse.success === false)) {
+ options.log("Upload success request was rejected by the server.", "error");
+ promise.failure(qq.extend(parsedResponse, failureIndicator));
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(qq.extend(parsedResponse, successIndicator));
+ }
+ } catch (error) {
+ if (isError) {
+ options.log(qq.format("Your server indicated failure in its upload success request response for id {}!", id), "error");
+ promise.failure(failureIndicator);
+ } else {
+ options.log("Upload success was acknowledged by the server.");
+ promise.success(successIndicator);
+ }
+ }
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ method: options.method,
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ paramsStore: options.paramsStore,
+ maxConnections: options.maxConnections,
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: handleSuccessResponse,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendSuccessRequest: function(id, spec) {
+ var promise = new qq.Promise();
+ options.log("Submitting upload success request/notification for " + id);
+ requester.initTransport(id).withParams(spec).send();
+ pendingRequests[id] = promise;
+ return promise;
+ }
+ });
+ };
+ qq.azure.DeleteBlob = function(o) {
+ "use strict";
+ var requester, method = "DELETE", options = {
+ endpointStore: {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhr, isError) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 202 ];
+ return codes;
+ }(),
+ contentType: null,
+ endpointStore: options.endpointStore,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete
+ }));
+ qq.extend(this, {
+ method: method,
+ send: function(id) {
+ options.log("Submitting Delete Blob request for " + id);
+ return requester.initTransport(id).send();
+ }
+ });
+ };
+ qq.azure.PutBlob = function(o) {
+ "use strict";
+ var requester, method = "PUT", options = {
+ getBlobMetadata: function(id) {},
+ log: function(str, level) {}
+ }, endpoints = {}, promises = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ contentType: null,
+ customHeaders: function(id) {
+ var params = options.getBlobMetadata(id), headers = qq.azure.util.getParamsAsHeaders(params);
+ headers["x-ms-blob-type"] = "BlockBlob";
+ return headers;
+ },
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id];
+ delete endpoints[id];
+ delete promises[id];
+ if (isError) {
+ promise.failure();
+ } else {
+ promise.success();
+ }
+ }
+ }));
+ qq.extend(this, {
+ method: method,
+ upload: function(id, xhr, url, file) {
+ var promise = new qq.Promise();
+ options.log("Submitting Put Blob request for " + id);
+ promises[id] = promise;
+ endpoints[id] = url;
+ requester.initTransport(id).withPayload(file).withHeaders({
+ "Content-Type": file.type
+ }).send(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.azure.PutBlock = function(o) {
+ "use strict";
+ var requester, method = "PUT", blockIdEntries = {}, promises = {}, options = {
+ log: function(str, level) {}
+ }, endpoints = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ contentType: null,
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id], blockIdEntry = blockIdEntries[id];
+ delete endpoints[id];
+ delete promises[id];
+ delete blockIdEntries[id];
+ if (isError) {
+ promise.failure();
+ } else {
+ promise.success(blockIdEntry);
+ }
+ }
+ }));
+ function createBlockId(partNum) {
+ var digits = 5, zeros = new Array(digits + 1).join("0"), paddedPartNum = (zeros + partNum).slice(-digits);
+ return btoa(paddedPartNum);
+ }
+ qq.extend(this, {
+ method: method,
+ upload: function(id, xhr, sasUri, partNum, blob) {
+ var promise = new qq.Promise(), blockId = createBlockId(partNum);
+ promises[id] = promise;
+ options.log(qq.format("Submitting Put Block request for {} = part {}", id, partNum));
+ endpoints[id] = qq.format("{}&comp=block&blockid={}", sasUri, encodeURIComponent(blockId));
+ blockIdEntries[id] = {
+ part: partNum,
+ id: blockId
+ };
+ requester.initTransport(id).withPayload(blob).send(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.azure.PutBlockList = function(o) {
+ "use strict";
+ var requester, method = "PUT", promises = {}, options = {
+ getBlobMetadata: function(id) {},
+ log: function(str, level) {}
+ }, endpoints = {}, endpointHandler = {
+ get: function(id) {
+ return endpoints[id];
+ }
+ };
+ qq.extend(options, o);
+ requester = qq.extend(this, new qq.AjaxRequester({
+ validMethods: [ method ],
+ method: method,
+ successfulResponseCodes: function() {
+ var codes = {};
+ codes[method] = [ 201 ];
+ return codes;
+ }(),
+ customHeaders: function(id) {
+ var params = options.getBlobMetadata(id);
+ return qq.azure.util.getParamsAsHeaders(params);
+ },
+ contentType: "text/plain",
+ endpointStore: endpointHandler,
+ allowXRequestedWithAndCacheControl: false,
+ cors: {
+ expected: true
+ },
+ log: options.log,
+ onSend: function() {},
+ onComplete: function(id, xhr, isError) {
+ var promise = promises[id];
+ delete endpoints[id];
+ delete promises[id];
+ if (isError) {
+ promise.failure(xhr);
+ } else {
+ promise.success(xhr);
+ }
+ }
+ }));
+ function createRequestBody(blockIdEntries) {
+ var doc = document.implementation.createDocument(null, "BlockList", null);
+ blockIdEntries.sort(function(a, b) {
+ return a.part - b.part;
+ });
+ qq.each(blockIdEntries, function(idx, blockIdEntry) {
+ var latestEl = doc.createElement("Latest"), latestTextEl = doc.createTextNode(blockIdEntry.id);
+ latestEl.appendChild(latestTextEl);
+ qq(doc).children()[0].appendChild(latestEl);
+ });
+ return new XMLSerializer().serializeToString(doc);
+ }
+ qq.extend(this, {
+ method: method,
+ send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {
+ var promise = new qq.Promise(), blockIdsXml = createRequestBody(blockIdEntries), xhr;
+ promises[id] = promise;
+ options.log(qq.format("Submitting Put Block List request for {}", id));
+ endpoints[id] = qq.format("{}&comp=blocklist", sasUri);
+ xhr = requester.initTransport(id).withPayload(blockIdsXml).withHeaders({
+ "x-ms-blob-content-type": fileMimeType
+ }).send();
+ registerXhrCallback(xhr);
+ return promise;
+ }
+ });
+ };
+ qq.DragAndDrop = function(o) {
+ "use strict";
+ var options, HIDE_ZONES_EVENT_NAME = "qq-hidezones", HIDE_BEFORE_ENTER_ATTR = "qq-hide-dropzone", uploadDropZones = [], droppedFiles = [], disposeSupport = new qq.DisposeSupport();
+ options = {
+ dropZoneElements: [],
+ allowMultipleItems: true,
+ classes: {
+ dropActive: null
+ },
+ callbacks: new qq.DragAndDrop.callbacks()
+ };
+ qq.extend(options, o, true);
+ function uploadDroppedFiles(files, uploadDropZone) {
+ var filesAsArray = Array.prototype.slice.call(files);
+ options.callbacks.dropLog("Grabbed " + files.length + " dropped files.");
+ uploadDropZone.dropDisabled(false);
+ options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());
+ }
+ function traverseFileTree(entry) {
+ var parseEntryPromise = new qq.Promise();
+ if (entry.isFile) {
+ entry.file(function(file) {
+ var name = entry.name, fullPath = entry.fullPath, indexOfNameInFullPath = fullPath.indexOf(name);
+ fullPath = fullPath.substr(0, indexOfNameInFullPath);
+ if (fullPath.charAt(0) === "/") {
+ fullPath = fullPath.substr(1);
+ }
+ file.qqPath = fullPath;
+ droppedFiles.push(file);
+ parseEntryPromise.success();
+ }, function(fileError) {
+ options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error");
+ parseEntryPromise.failure();
+ });
+ } else if (entry.isDirectory) {
+ getFilesInDirectory(entry).then(function allEntriesRead(entries) {
+ var entriesLeft = entries.length;
+ qq.each(entries, function(idx, entry) {
+ traverseFileTree(entry).done(function() {
+ entriesLeft -= 1;
+ if (entriesLeft === 0) {
+ parseEntryPromise.success();
+ }
+ });
+ });
+ if (!entries.length) {
+ parseEntryPromise.success();
+ }
+ }, function readFailure(fileError) {
+ options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error");
+ parseEntryPromise.failure();
+ });
+ }
+ return parseEntryPromise;
+ }
+ function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {
+ var promise = existingPromise || new qq.Promise(), dirReader = reader || entry.createReader();
+ dirReader.readEntries(function readSuccess(entries) {
+ var newEntries = accumEntries ? accumEntries.concat(entries) : entries;
+ if (entries.length) {
+ setTimeout(function() {
+ getFilesInDirectory(entry, dirReader, newEntries, promise);
+ }, 0);
+ } else {
+ promise.success(newEntries);
+ }
+ }, promise.failure);
+ return promise;
+ }
+ function handleDataTransfer(dataTransfer, uploadDropZone) {
+ var pendingFolderPromises = [], handleDataTransferPromise = new qq.Promise();
+ options.callbacks.processingDroppedFiles();
+ uploadDropZone.dropDisabled(true);
+ if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {
+ options.callbacks.processingDroppedFilesComplete([]);
+ options.callbacks.dropError("tooManyFilesError", "");
+ uploadDropZone.dropDisabled(false);
+ handleDataTransferPromise.failure();
+ } else {
+ droppedFiles = [];
+ if (qq.isFolderDropSupported(dataTransfer)) {
+ qq.each(dataTransfer.items, function(idx, item) {
+ var entry = item.webkitGetAsEntry();
+ if (entry) {
+ if (entry.isFile) {
+ droppedFiles.push(item.getAsFile());
+ } else {
+ pendingFolderPromises.push(traverseFileTree(entry).done(function() {
+ pendingFolderPromises.pop();
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }));
+ }
+ }
+ });
+ } else {
+ droppedFiles = dataTransfer.files;
+ }
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }
+ return handleDataTransferPromise;
+ }
+ function setupDropzone(dropArea) {
+ var dropZone = new qq.UploadDropZone({
+ HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,
+ element: dropArea,
+ onEnter: function(e) {
+ qq(dropArea).addClass(options.classes.dropActive);
+ e.stopPropagation();
+ },
+ onLeaveNotDescendants: function(e) {
+ qq(dropArea).removeClass(options.classes.dropActive);
+ },
+ onDrop: function(e) {
+ handleDataTransfer(e.dataTransfer, dropZone).then(function() {
+ uploadDroppedFiles(droppedFiles, dropZone);
+ }, function() {
+ options.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.", "error");
+ });
+ }
+ });
+ disposeSupport.addDisposer(function() {
+ dropZone.dispose();
+ });
+ qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();
+ uploadDropZones.push(dropZone);
+ return dropZone;
+ }
+ function isFileDrag(dragEvent) {
+ var fileDrag;
+ qq.each(dragEvent.dataTransfer.types, function(key, val) {
+ if (val === "Files") {
+ fileDrag = true;
+ return false;
+ }
+ });
+ return fileDrag;
+ }
+ function leavingDocumentOut(e) {
+ if (qq.firefox()) {
+ return !e.relatedTarget;
+ }
+ if (qq.safari()) {
+ return e.x < 0 || e.y < 0;
+ }
+ return e.x === 0 && e.y === 0;
+ }
+ function setupDragDrop() {
+ var dropZones = options.dropZoneElements, maybeHideDropZones = function() {
+ setTimeout(function() {
+ qq.each(dropZones, function(idx, dropZone) {
+ qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();
+ qq(dropZone).removeClass(options.classes.dropActive);
+ });
+ }, 10);
+ };
+ qq.each(dropZones, function(idx, dropZone) {
+ var uploadDropZone = setupDropzone(dropZone);
+ if (dropZones.length && qq.supportedFeatures.fileDrop) {
+ disposeSupport.attach(document, "dragenter", function(e) {
+ if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {
+ qq.each(dropZones, function(idx, dropZone) {
+ if (dropZone instanceof HTMLElement && qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {
+ qq(dropZone).css({
+ display: "block"
+ });
+ }
+ });
+ }
+ });
+ }
+ });
+ disposeSupport.attach(document, "dragleave", function(e) {
+ if (leavingDocumentOut(e)) {
+ maybeHideDropZones();
+ }
+ });
+ disposeSupport.attach(qq(document).children()[0], "mouseenter", function(e) {
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, "drop", function(e) {
+ e.preventDefault();
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);
+ }
+ setupDragDrop();
+ qq.extend(this, {
+ setupExtraDropzone: function(element) {
+ options.dropZoneElements.push(element);
+ setupDropzone(element);
+ },
+ removeDropzone: function(element) {
+ var i, dzs = options.dropZoneElements;
+ for (i in dzs) {
+ if (dzs[i] === element) {
+ return dzs.splice(i, 1);
+ }
+ }
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ qq.each(uploadDropZones, function(idx, dropZone) {
+ dropZone.dispose();
+ });
+ }
+ });
+ };
+ qq.DragAndDrop.callbacks = function() {
+ "use strict";
+ return {
+ processingDroppedFiles: function() {},
+ processingDroppedFilesComplete: function(files, targetEl) {},
+ dropError: function(code, errorSpecifics) {
+ qq.log("Drag & drop error code '" + code + " with these specifics: '" + errorSpecifics + "'", "error");
+ },
+ dropLog: function(message, level) {
+ qq.log(message, level);
+ }
+ };
+ };
+ qq.UploadDropZone = function(o) {
+ "use strict";
+ var disposeSupport = new qq.DisposeSupport(), options, element, preventDrop, dropOutsideDisabled;
+ options = {
+ element: null,
+ onEnter: function(e) {},
+ onLeave: function(e) {},
+ onLeaveNotDescendants: function(e) {},
+ onDrop: function(e) {}
+ };
+ qq.extend(options, o);
+ element = options.element;
+ function dragoverShouldBeCanceled() {
+ return qq.safari() || qq.firefox() && qq.windows();
+ }
+ function disableDropOutside(e) {
+ if (!dropOutsideDisabled) {
+ if (dragoverShouldBeCanceled) {
+ disposeSupport.attach(document, "dragover", function(e) {
+ e.preventDefault();
+ });
+ } else {
+ disposeSupport.attach(document, "dragover", function(e) {
+ if (e.dataTransfer) {
+ e.dataTransfer.dropEffect = "none";
+ e.preventDefault();
+ }
+ });
+ }
+ dropOutsideDisabled = true;
+ }
+ }
+ function isValidFileDrag(e) {
+ if (!qq.supportedFeatures.fileDrop) {
+ return false;
+ }
+ var effectTest, dt = e.dataTransfer, isSafari = qq.safari();
+ effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== "none";
+ return dt && effectTest && (dt.files || !isSafari && dt.types.contains && dt.types.contains("Files"));
+ }
+ function isOrSetDropDisabled(isDisabled) {
+ if (isDisabled !== undefined) {
+ preventDrop = isDisabled;
+ }
+ return preventDrop;
+ }
+ function triggerHidezonesEvent() {
+ var hideZonesEvent;
+ function triggerUsingOldApi() {
+ hideZonesEvent = document.createEvent("Event");
+ hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);
+ }
+ if (window.CustomEvent) {
+ try {
+ hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);
+ } catch (err) {
+ triggerUsingOldApi();
+ }
+ } else {
+ triggerUsingOldApi();
+ }
+ document.dispatchEvent(hideZonesEvent);
+ }
+ function attachEvents() {
+ disposeSupport.attach(element, "dragover", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;
+ if (effect === "move" || effect === "linkMove") {
+ e.dataTransfer.dropEffect = "move";
+ } else {
+ e.dataTransfer.dropEffect = "copy";
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ disposeSupport.attach(element, "dragenter", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onEnter(e);
+ }
+ });
+ disposeSupport.attach(element, "dragleave", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onLeave(e);
+ var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
+ if (qq(this).contains(relatedTarget)) {
+ return;
+ }
+ options.onLeaveNotDescendants(e);
+ });
+ disposeSupport.attach(element, "drop", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ options.onDrop(e);
+ triggerHidezonesEvent();
+ }
+ });
+ }
+ disableDropOutside();
+ attachEvents();
+ qq.extend(this, {
+ dropDisabled: function(isDisabled) {
+ return isOrSetDropDisabled(isDisabled);
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ },
+ getElement: function() {
+ return element;
+ }
+ });
+ };
+ (function() {
+ "use strict";
+ qq.uiPublicApi = {
+ addInitialFiles: function(cannedFileList) {
+ this._parent.prototype.addInitialFiles.apply(this, arguments);
+ this._templating.addCacheToDom();
+ },
+ clearStoredFiles: function() {
+ this._parent.prototype.clearStoredFiles.apply(this, arguments);
+ this._templating.clearFiles();
+ },
+ addExtraDropzone: function(element) {
+ this._dnd && this._dnd.setupExtraDropzone(element);
+ },
+ removeExtraDropzone: function(element) {
+ if (this._dnd) {
+ return this._dnd.removeDropzone(element);
+ }
+ },
+ getItemByFileId: function(id) {
+ if (!this._templating.isHiddenForever(id)) {
+ return this._templating.getFileContainer(id);
+ }
+ },
+ reset: function() {
+ this._parent.prototype.reset.apply(this, arguments);
+ this._templating.reset();
+ if (!this._options.button && this._templating.getButton()) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._templating.getButton(),
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ if (this._dnd) {
+ this._dnd.dispose();
+ this._dnd = this._setupDragAndDrop();
+ }
+ this._totalFilesInBatch = 0;
+ this._filesInBatchAddedToUi = 0;
+ this._setupClickAndEditEventHandlers();
+ },
+ setName: function(id, newName) {
+ var formattedFilename = this._options.formatFileName(newName);
+ this._parent.prototype.setName.apply(this, arguments);
+ this._templating.updateFilename(id, formattedFilename);
+ },
+ pauseUpload: function(id) {
+ var paused = this._parent.prototype.pauseUpload.apply(this, arguments);
+ paused && this._templating.uploadPaused(id);
+ return paused;
+ },
+ continueUpload: function(id) {
+ var continued = this._parent.prototype.continueUpload.apply(this, arguments);
+ continued && this._templating.uploadContinued(id);
+ return continued;
+ },
+ getId: function(fileContainerOrChildEl) {
+ return this._templating.getFileId(fileContainerOrChildEl);
+ },
+ getDropTarget: function(fileId) {
+ var file = this.getFile(fileId);
+ return file.qqDropTarget;
+ }
+ };
+ qq.uiPrivateApi = {
+ _getButton: function(buttonId) {
+ var button = this._parent.prototype._getButton.apply(this, arguments);
+ if (!button) {
+ if (buttonId === this._defaultButtonId) {
+ button = this._templating.getButton();
+ }
+ }
+ return button;
+ },
+ _removeFileItem: function(fileId) {
+ this._templating.removeFile(fileId);
+ },
+ _setupClickAndEditEventHandlers: function() {
+ this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();
+ this._focusinEventSupported = !qq.firefox();
+ if (this._isEditFilenameEnabled()) {
+ this._filenameClickHandler = this._bindFilenameClickEvent();
+ this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();
+ this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();
+ }
+ },
+ _setupDragAndDrop: function() {
+ var self = this, dropZoneElements = this._options.dragAndDrop.extraDropzones, templating = this._templating, defaultDropZone = templating.getDropZone();
+ defaultDropZone && dropZoneElements.push(defaultDropZone);
+ return new qq.DragAndDrop({
+ dropZoneElements: dropZoneElements,
+ allowMultipleItems: this._options.multiple,
+ classes: {
+ dropActive: this._options.classes.dropActive
+ },
+ callbacks: {
+ processingDroppedFiles: function() {
+ templating.showDropProcessing();
+ },
+ processingDroppedFilesComplete: function(files, targetEl) {
+ templating.hideDropProcessing();
+ qq.each(files, function(idx, file) {
+ file.qqDropTarget = targetEl;
+ });
+ if (files.length) {
+ self.addFiles(files, null, null);
+ }
+ },
+ dropError: function(code, errorData) {
+ self._itemError(code, errorData);
+ },
+ dropLog: function(message, level) {
+ self.log(message, level);
+ }
+ }
+ });
+ },
+ _bindFileButtonsClickEvent: function() {
+ var self = this;
+ return new qq.FileButtonsClickHandler({
+ templating: this._templating,
+ log: function(message, lvl) {
+ self.log(message, lvl);
+ },
+ onDeleteFile: function(fileId) {
+ self.deleteFile(fileId);
+ },
+ onCancel: function(fileId) {
+ self.cancel(fileId);
+ },
+ onRetry: function(fileId) {
+ self.retry(fileId);
+ },
+ onPause: function(fileId) {
+ self.pauseUpload(fileId);
+ },
+ onContinue: function(fileId) {
+ self.continueUpload(fileId);
+ },
+ onGetName: function(fileId) {
+ return self.getName(fileId);
+ }
+ });
+ },
+ _isEditFilenameEnabled: function() {
+ return this._templating.isEditFilenamePossible() && !this._options.autoUpload && qq.FilenameClickHandler && qq.FilenameInputFocusHandler && qq.FilenameInputFocusHandler;
+ },
+ _filenameEditHandler: function() {
+ var self = this, templating = this._templating;
+ return {
+ templating: templating,
+ log: function(message, lvl) {
+ self.log(message, lvl);
+ },
+ onGetUploadStatus: function(fileId) {
+ return self.getUploads({
+ id: fileId
+ }).status;
+ },
+ onGetName: function(fileId) {
+ return self.getName(fileId);
+ },
+ onSetName: function(id, newName) {
+ self.setName(id, newName);
+ },
+ onEditingStatusChange: function(id, isEditing) {
+ var qqInput = qq(templating.getEditInput(id)), qqFileContainer = qq(templating.getFileContainer(id));
+ if (isEditing) {
+ qqInput.addClass("qq-editing");
+ templating.hideFilename(id);
+ templating.hideEditIcon(id);
+ } else {
+ qqInput.removeClass("qq-editing");
+ templating.showFilename(id);
+ templating.showEditIcon(id);
+ }
+ qqFileContainer.addClass("qq-temp").removeClass("qq-temp");
+ }
+ };
+ },
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ this._parent.prototype._onUploadStatusChange.apply(this, arguments);
+ if (this._isEditFilenameEnabled()) {
+ if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {
+ this._templating.markFilenameEditable(id);
+ this._templating.hideEditIcon(id);
+ }
+ }
+ if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {
+ this._templating.hideRetry(id);
+ this._templating.setStatusText(id);
+ qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);
+ } else if (newStatus === qq.status.UPLOAD_FAILED) {
+ this._templating.hidePause(id);
+ }
+ },
+ _bindFilenameInputFocusInEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameInputFocusInHandler(spec);
+ },
+ _bindFilenameInputFocusEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameInputFocusHandler(spec);
+ },
+ _bindFilenameClickEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameClickHandler(spec);
+ },
+ _storeForLater: function(id) {
+ this._parent.prototype._storeForLater.apply(this, arguments);
+ this._templating.hideSpinner(id);
+ },
+ _onAllComplete: function(successful, failed) {
+ this._parent.prototype._onAllComplete.apply(this, arguments);
+ this._templating.resetTotalProgress();
+ },
+ _onSubmit: function(id, name) {
+ var file = this.getFile(id);
+ if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {
+ this._paramsStore.addReadOnly(id, {
+ qqpath: file.qqPath
+ });
+ }
+ this._parent.prototype._onSubmit.apply(this, arguments);
+ this._addToList(id, name);
+ },
+ _onSubmitted: function(id) {
+ if (this._isEditFilenameEnabled()) {
+ this._templating.markFilenameEditable(id);
+ this._templating.showEditIcon(id);
+ if (!this._focusinEventSupported) {
+ this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));
+ }
+ }
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._parent.prototype._onProgress.apply(this, arguments);
+ this._templating.updateProgress(id, loaded, total);
+ if (total === 0 || Math.round(loaded / total * 100) === 100) {
+ this._templating.hideCancel(id);
+ this._templating.hidePause(id);
+ this._templating.hideProgress(id);
+ this._templating.setStatusText(id, this._options.text.waitingForResponse);
+ this._displayFileSize(id);
+ } else {
+ this._displayFileSize(id, loaded, total);
+ }
+ },
+ _onTotalProgress: function(loaded, total) {
+ this._parent.prototype._onTotalProgress.apply(this, arguments);
+ this._templating.updateTotalProgress(loaded, total);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments), templating = this._templating, fileContainer = templating.getFileContainer(id), self = this;
+ function completeUpload(result) {
+ if (!fileContainer) {
+ return;
+ }
+ templating.setStatusText(id);
+ qq(fileContainer).removeClass(self._classes.retrying);
+ templating.hideProgress(id);
+ if (self.getUploads({
+ id: id
+ }).status !== qq.status.UPLOAD_FAILED) {
+ templating.hideCancel(id);
+ }
+ templating.hideSpinner(id);
+ if (result.success) {
+ self._markFileAsSuccessful(id);
+ } else {
+ qq(fileContainer).addClass(self._classes.fail);
+ templating.showCancel(id);
+ if (templating.isRetryPossible() && !self._preventRetries[id]) {
+ qq(fileContainer).addClass(self._classes.retryable);
+ templating.showRetry(id);
+ }
+ self._controlFailureTextDisplay(id, result);
+ }
+ }
+ if (parentRetVal instanceof qq.Promise) {
+ parentRetVal.done(function(newResult) {
+ completeUpload(newResult);
+ });
+ } else {
+ completeUpload(result);
+ }
+ return parentRetVal;
+ },
+ _markFileAsSuccessful: function(id) {
+ var templating = this._templating;
+ if (this._isDeletePossible()) {
+ templating.showDeleteButton(id);
+ }
+ qq(templating.getFileContainer(id)).addClass(this._classes.success);
+ this._maybeUpdateThumbnail(id);
+ },
+ _onUploadPrep: function(id) {
+ this._parent.prototype._onUploadPrep.apply(this, arguments);
+ this._templating.showSpinner(id);
+ },
+ _onUpload: function(id, name) {
+ var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);
+ this._templating.showSpinner(id);
+ return parentRetVal;
+ },
+ _onUploadChunk: function(id, chunkData) {
+ this._parent.prototype._onUploadChunk.apply(this, arguments);
+ if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {
+ this._templating.allowPause(id);
+ }
+ },
+ _onCancel: function(id, name) {
+ this._parent.prototype._onCancel.apply(this, arguments);
+ this._removeFileItem(id);
+ if (this._getNotFinished() === 0) {
+ this._templating.resetTotalProgress();
+ }
+ },
+ _onBeforeAutoRetry: function(id) {
+ var retryNumForDisplay, maxAuto, retryNote;
+ this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);
+ this._showCancelLink(id);
+ if (this._options.retry.showAutoRetryNote) {
+ retryNumForDisplay = this._autoRetries[id];
+ maxAuto = this._options.retry.maxAutoAttempts;
+ retryNote = this._options.retry.autoRetryNote.replace(/\{retryNum\}/g, retryNumForDisplay);
+ retryNote = retryNote.replace(/\{maxAuto\}/g, maxAuto);
+ this._templating.setStatusText(id, retryNote);
+ qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);
+ }
+ },
+ _onBeforeManualRetry: function(id) {
+ if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {
+ this._templating.resetProgress(id);
+ qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);
+ this._templating.setStatusText(id);
+ this._templating.showSpinner(id);
+ this._showCancelLink(id);
+ return true;
+ } else {
+ qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);
+ this._templating.showRetry(id);
+ return false;
+ }
+ },
+ _onSubmitDelete: function(id) {
+ var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);
+ this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);
+ },
+ _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {
+ if (this._options.deleteFile.forceConfirm) {
+ this._showDeleteConfirm.apply(this, arguments);
+ } else {
+ this._sendDeleteRequest.apply(this, arguments);
+ }
+ },
+ _onDeleteComplete: function(id, xhr, isError) {
+ this._parent.prototype._onDeleteComplete.apply(this, arguments);
+ this._templating.hideSpinner(id);
+ if (isError) {
+ this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);
+ this._templating.showDeleteButton(id);
+ } else {
+ this._removeFileItem(id);
+ }
+ },
+ _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {
+ this._templating.hideDeleteButton(id);
+ this._templating.showSpinner(id);
+ this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);
+ this._deleteHandler.sendDelete.apply(this, arguments);
+ },
+ _showDeleteConfirm: function(id, uuid, mandatedParams) {
+ var fileName = this.getName(id), confirmMessage = this._options.deleteFile.confirmMessage.replace(/\{filename\}/g, fileName), uuid = this.getUuid(id), deleteRequestArgs = arguments, self = this, retVal;
+ retVal = this._options.showConfirm(confirmMessage);
+ if (qq.isGenericPromise(retVal)) {
+ retVal.then(function() {
+ self._sendDeleteRequest.apply(self, deleteRequestArgs);
+ });
+ } else if (retVal !== false) {
+ self._sendDeleteRequest.apply(self, deleteRequestArgs);
+ }
+ },
+ _addToList: function(id, name, canned) {
+ var prependData, prependIndex = 0, dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled, record;
+ if (this._options.display.prependFiles) {
+ if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {
+ prependIndex = this._filesInBatchAddedToUi - 1;
+ }
+ prependData = {
+ index: prependIndex
+ };
+ }
+ if (!canned) {
+ if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {
+ this._templating.disableCancel();
+ }
+ if (!this._options.multiple) {
+ record = this.getUploads({
+ id: id
+ });
+ this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;
+ if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {
+ this._handler.cancelAll();
+ this._clearList();
+ this._handledProxyGroup = null;
+ }
+ }
+ }
+ if (canned) {
+ this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);
+ this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);
+ } else {
+ this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);
+ this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);
+ }
+ this._filesInBatchAddedToUi += 1;
+ if (canned || this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading) {
+ this._displayFileSize(id);
+ }
+ },
+ _clearList: function() {
+ this._templating.clearFiles();
+ this.clearStoredFiles();
+ },
+ _displayFileSize: function(id, loadedSize, totalSize) {
+ var size = this.getSize(id), sizeForDisplay = this._formatSize(size);
+ if (size >= 0) {
+ if (loadedSize !== undefined && totalSize !== undefined) {
+ sizeForDisplay = this._formatProgress(loadedSize, totalSize);
+ }
+ this._templating.updateSize(id, sizeForDisplay);
+ }
+ },
+ _formatProgress: function(uploadedSize, totalSize) {
+ var message = this._options.text.formatProgress;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ r("{percent}", Math.round(uploadedSize / totalSize * 100));
+ r("{total_size}", this._formatSize(totalSize));
+ return message;
+ },
+ _controlFailureTextDisplay: function(id, response) {
+ var mode, responseProperty, failureReason;
+ mode = this._options.failedUploadTextDisplay.mode;
+ responseProperty = this._options.failedUploadTextDisplay.responseProperty;
+ if (mode === "custom") {
+ failureReason = response[responseProperty];
+ if (!failureReason) {
+ failureReason = this._options.text.failUpload;
+ }
+ this._templating.setStatusText(id, failureReason);
+ if (this._options.failedUploadTextDisplay.enableTooltip) {
+ this._showTooltip(id, failureReason);
+ }
+ } else if (mode === "default") {
+ this._templating.setStatusText(id, this._options.text.failUpload);
+ } else if (mode !== "none") {
+ this.log("failedUploadTextDisplay.mode value of '" + mode + "' is not valid", "warn");
+ }
+ },
+ _showTooltip: function(id, text) {
+ this._templating.getFileContainer(id).title = text;
+ },
+ _showCancelLink: function(id) {
+ if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {
+ this._templating.showCancel(id);
+ }
+ },
+ _itemError: function(code, name, item) {
+ var message = this._parent.prototype._itemError.apply(this, arguments);
+ this._options.showMessage(message);
+ },
+ _batchError: function(message) {
+ this._parent.prototype._batchError.apply(this, arguments);
+ this._options.showMessage(message);
+ },
+ _setupPastePrompt: function() {
+ var self = this;
+ this._options.callbacks.onPasteReceived = function() {
+ var message = self._options.paste.namePromptMessage, defaultVal = self._options.paste.defaultName;
+ return self._options.showPrompt(message, defaultVal);
+ };
+ },
+ _fileOrBlobRejected: function(id, name) {
+ this._totalFilesInBatch -= 1;
+ this._parent.prototype._fileOrBlobRejected.apply(this, arguments);
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ this._totalFilesInBatch = items.length;
+ this._filesInBatchAddedToUi = 0;
+ this._parent.prototype._prepareItemsForUpload.apply(this, arguments);
+ },
+ _maybeUpdateThumbnail: function(fileId) {
+ var thumbnailUrl = this._thumbnailUrls[fileId], fileStatus = this.getUploads({
+ id: fileId
+ }).status;
+ if (fileStatus !== qq.status.DELETED && (thumbnailUrl || this._options.thumbnails.placeholders.waitUntilResponse || !qq.supportedFeatures.imagePreviews)) {
+ this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);
+ }
+ },
+ _addCannedFile: function(sessionData) {
+ var id = this._parent.prototype._addCannedFile.apply(this, arguments);
+ this._addToList(id, this.getName(id), true);
+ this._templating.hideSpinner(id);
+ this._templating.hideCancel(id);
+ this._markFileAsSuccessful(id);
+ return id;
+ },
+ _setSize: function(id, newSize) {
+ this._parent.prototype._setSize.apply(this, arguments);
+ this._templating.updateSize(id, this._formatSize(newSize));
+ },
+ _sessionRequestComplete: function() {
+ this._templating.addCacheToDom();
+ this._parent.prototype._sessionRequestComplete.apply(this, arguments);
+ }
+ };
+ })();
+ qq.FineUploader = function(o, namespace) {
+ "use strict";
+ var self = this;
+ this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;
+ this._parent.apply(this, arguments);
+ qq.extend(this._options, {
+ element: null,
+ button: null,
+ listElement: null,
+ dragAndDrop: {
+ extraDropzones: [],
+ reportDirectoryPaths: false
+ },
+ text: {
+ formatProgress: "{percent}% of {total_size}",
+ failUpload: "Upload failed",
+ waitingForResponse: "Processing...",
+ paused: "Paused"
+ },
+ template: "qq-template",
+ classes: {
+ retrying: "qq-upload-retrying",
+ retryable: "qq-upload-retryable",
+ success: "qq-upload-success",
+ fail: "qq-upload-fail",
+ editable: "qq-editable",
+ hide: "qq-hide",
+ dropActive: "qq-upload-drop-area-active"
+ },
+ failedUploadTextDisplay: {
+ mode: "default",
+ responseProperty: "error",
+ enableTooltip: true
+ },
+ messages: {
+ tooManyFilesError: "You may only drop one file",
+ unsupportedBrowser: "Unrecoverable error - this browser does not permit file uploading of any kind."
+ },
+ retry: {
+ showAutoRetryNote: true,
+ autoRetryNote: "Retrying {retryNum}/{maxAuto}..."
+ },
+ deleteFile: {
+ forceConfirm: false,
+ confirmMessage: "Are you sure you want to delete {filename}?",
+ deletingStatusText: "Deleting...",
+ deletingFailedText: "Delete failed"
+ },
+ display: {
+ fileSizeOnSubmit: false,
+ prependFiles: false
+ },
+ paste: {
+ promptForName: false,
+ namePromptMessage: "Please name this image"
+ },
+ thumbnails: {
+ customResizer: null,
+ maxCount: 0,
+ placeholders: {
+ waitUntilResponse: false,
+ notAvailablePath: null,
+ waitingPath: null
+ },
+ timeBetweenThumbs: 750
+ },
+ scaling: {
+ hideScaled: false
+ },
+ showMessage: function(message) {
+ if (self._templating.hasDialog("alert")) {
+ return self._templating.showDialog("alert", message);
+ } else {
+ setTimeout(function() {
+ window.alert(message);
+ }, 0);
+ }
+ },
+ showConfirm: function(message) {
+ if (self._templating.hasDialog("confirm")) {
+ return self._templating.showDialog("confirm", message);
+ } else {
+ return window.confirm(message);
+ }
+ },
+ showPrompt: function(message, defaultValue) {
+ if (self._templating.hasDialog("prompt")) {
+ return self._templating.showDialog("prompt", message, defaultValue);
+ } else {
+ return window.prompt(message, defaultValue);
+ }
+ }
+ }, true);
+ qq.extend(this._options, o, true);
+ this._templating = new qq.Templating({
+ log: qq.bind(this.log, this),
+ templateIdOrEl: this._options.template,
+ containerEl: this._options.element,
+ fileContainerEl: this._options.listElement,
+ button: this._options.button,
+ imageGenerator: this._imageGenerator,
+ classes: {
+ hide: this._options.classes.hide,
+ editable: this._options.classes.editable
+ },
+ limits: {
+ maxThumbs: this._options.thumbnails.maxCount,
+ timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs
+ },
+ placeholders: {
+ waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,
+ thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,
+ waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath
+ },
+ text: this._options.text
+ });
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);
+ } else if (!qq.supportedFeatures.uploading || this._options.cors.expected && !qq.supportedFeatures.uploadCors) {
+ this._templating.renderFailure(this._options.messages.unsupportedBrowser);
+ } else {
+ this._wrapCallbacks();
+ this._templating.render();
+ this._classes = this._options.classes;
+ if (!this._options.button && this._templating.getButton()) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._templating.getButton(),
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._setupClickAndEditEventHandlers();
+ if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {
+ this._dnd = this._setupDragAndDrop();
+ }
+ if (this._options.paste.targetElement && this._options.paste.promptForName) {
+ if (qq.PasteSupport) {
+ this._setupPastePrompt();
+ } else {
+ this.log("Paste support module not found.", "error");
+ }
+ }
+ this._totalFilesInBatch = 0;
+ this._filesInBatchAddedToUi = 0;
+ }
+ };
+ qq.extend(qq.FineUploader.prototype, qq.basePublicApi);
+ qq.extend(qq.FineUploader.prototype, qq.basePrivateApi);
+ qq.extend(qq.FineUploader.prototype, qq.uiPublicApi);
+ qq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);
+ qq.Templating = function(spec) {
+ "use strict";
+ var FILE_ID_ATTR = "qq-file-id", FILE_CLASS_PREFIX = "qq-file-id-", THUMBNAIL_MAX_SIZE_ATTR = "qq-max-size", THUMBNAIL_SERVER_SCALE_ATTR = "qq-server-scale", HIDE_DROPZONE_ATTR = "qq-hide-dropzone", DROPZPONE_TEXT_ATTR = "qq-drop-area-text", IN_PROGRESS_CLASS = "qq-in-progress", HIDDEN_FOREVER_CLASS = "qq-hidden-forever", fileBatch = {
+ content: document.createDocumentFragment(),
+ map: {}
+ }, isCancelDisabled = false, generatedThumbnails = 0, thumbnailQueueMonitorRunning = false, thumbGenerationQueue = [], thumbnailMaxSize = -1, options = {
+ log: null,
+ limits: {
+ maxThumbs: 0,
+ timeBetweenThumbs: 750
+ },
+ templateIdOrEl: "qq-template",
+ containerEl: null,
+ fileContainerEl: null,
+ button: null,
+ imageGenerator: null,
+ classes: {
+ hide: "qq-hide",
+ editable: "qq-editable"
+ },
+ placeholders: {
+ waitUntilUpdate: false,
+ thumbnailNotAvailable: null,
+ waitingForThumbnail: null
+ },
+ text: {
+ paused: "Paused"
+ }
+ }, selectorClasses = {
+ button: "qq-upload-button-selector",
+ alertDialog: "qq-alert-dialog-selector",
+ dialogCancelButton: "qq-cancel-button-selector",
+ confirmDialog: "qq-confirm-dialog-selector",
+ dialogMessage: "qq-dialog-message-selector",
+ dialogOkButton: "qq-ok-button-selector",
+ promptDialog: "qq-prompt-dialog-selector",
+ uploader: "qq-uploader-selector",
+ drop: "qq-upload-drop-area-selector",
+ list: "qq-upload-list-selector",
+ progressBarContainer: "qq-progress-bar-container-selector",
+ progressBar: "qq-progress-bar-selector",
+ totalProgressBarContainer: "qq-total-progress-bar-container-selector",
+ totalProgressBar: "qq-total-progress-bar-selector",
+ file: "qq-upload-file-selector",
+ spinner: "qq-upload-spinner-selector",
+ size: "qq-upload-size-selector",
+ cancel: "qq-upload-cancel-selector",
+ pause: "qq-upload-pause-selector",
+ continueButton: "qq-upload-continue-selector",
+ deleteButton: "qq-upload-delete-selector",
+ retry: "qq-upload-retry-selector",
+ statusText: "qq-upload-status-text-selector",
+ editFilenameInput: "qq-edit-filename-selector",
+ editNameIcon: "qq-edit-filename-icon-selector",
+ dropText: "qq-upload-drop-area-text-selector",
+ dropProcessing: "qq-drop-processing-selector",
+ dropProcessingSpinner: "qq-drop-processing-spinner-selector",
+ thumbnail: "qq-thumbnail-selector"
+ }, previewGeneration = {}, cachedThumbnailNotAvailableImg = new qq.Promise(), cachedWaitingForThumbnailImg = new qq.Promise(), log, isEditElementsExist, isRetryElementExist, templateHtml, container, fileList, showThumbnails, serverScale, cacheThumbnailPlaceholders = function() {
+ var notAvailableUrl = options.placeholders.thumbnailNotAvailable, waitingUrl = options.placeholders.waitingForThumbnail, spec = {
+ maxSize: thumbnailMaxSize,
+ scale: serverScale
+ };
+ if (showThumbnails) {
+ if (notAvailableUrl) {
+ options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(function(updatedImg) {
+ cachedThumbnailNotAvailableImg.success(updatedImg);
+ }, function() {
+ cachedThumbnailNotAvailableImg.failure();
+ log("Problem loading 'not available' placeholder image at " + notAvailableUrl, "error");
+ });
+ } else {
+ cachedThumbnailNotAvailableImg.failure();
+ }
+ if (waitingUrl) {
+ options.imageGenerator.generate(waitingUrl, new Image(), spec).then(function(updatedImg) {
+ cachedWaitingForThumbnailImg.success(updatedImg);
+ }, function() {
+ cachedWaitingForThumbnailImg.failure();
+ log("Problem loading 'waiting for thumbnail' placeholder image at " + waitingUrl, "error");
+ });
+ } else {
+ cachedWaitingForThumbnailImg.failure();
+ }
+ }
+ }, displayWaitingImg = function(thumbnail) {
+ var waitingImgPlacement = new qq.Promise();
+ cachedWaitingForThumbnailImg.then(function(img) {
+ maybeScalePlaceholderViaCss(img, thumbnail);
+ if (!thumbnail.src) {
+ thumbnail.src = img.src;
+ thumbnail.onload = function() {
+ thumbnail.onload = null;
+ show(thumbnail);
+ waitingImgPlacement.success();
+ };
+ } else {
+ waitingImgPlacement.success();
+ }
+ }, function() {
+ hide(thumbnail);
+ waitingImgPlacement.success();
+ });
+ return waitingImgPlacement;
+ }, generateNewPreview = function(id, blob, spec) {
+ var thumbnail = getThumbnail(id);
+ log("Generating new thumbnail for " + id);
+ blob.qqThumbnailId = id;
+ return options.imageGenerator.generate(blob, thumbnail, spec).then(function() {
+ generatedThumbnails++;
+ show(thumbnail);
+ previewGeneration[id].success();
+ }, function() {
+ previewGeneration[id].failure();
+ if (!options.placeholders.waitUntilUpdate) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ }
+ });
+ }, generateNextQueuedPreview = function() {
+ if (thumbGenerationQueue.length) {
+ thumbnailQueueMonitorRunning = true;
+ var queuedThumbRequest = thumbGenerationQueue.shift();
+ if (queuedThumbRequest.update) {
+ processUpdateQueuedPreviewRequest(queuedThumbRequest);
+ } else {
+ processNewQueuedPreviewRequest(queuedThumbRequest);
+ }
+ } else {
+ thumbnailQueueMonitorRunning = false;
+ }
+ }, getCancel = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.cancel);
+ }, getContinue = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.continueButton);
+ }, getDialog = function(type) {
+ return getTemplateEl(container, selectorClasses[type + "Dialog"]);
+ }, getDelete = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.deleteButton);
+ }, getDropProcessing = function() {
+ return getTemplateEl(container, selectorClasses.dropProcessing);
+ }, getEditIcon = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.editNameIcon);
+ }, getFile = function(id) {
+ return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);
+ }, getFilename = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.file);
+ }, getPause = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.pause);
+ }, getProgress = function(id) {
+ if (id == null) {
+ return getTemplateEl(container, selectorClasses.totalProgressBarContainer) || getTemplateEl(container, selectorClasses.totalProgressBar);
+ }
+ return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) || getTemplateEl(getFile(id), selectorClasses.progressBar);
+ }, getRetry = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.retry);
+ }, getSize = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.size);
+ }, getSpinner = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.spinner);
+ }, getTemplateEl = function(context, cssClass) {
+ return context && qq(context).getFirstByClass(cssClass);
+ }, getThumbnail = function(id) {
+ return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);
+ }, hide = function(el) {
+ el && qq(el).addClass(options.classes.hide);
+ }, maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {
+ var maxWidth = placeholder.style.maxWidth, maxHeight = placeholder.style.maxHeight;
+ if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {
+ qq(thumbnail).css({
+ maxWidth: maxWidth,
+ maxHeight: maxHeight
+ });
+ }
+ }, maybeSetDisplayNotAvailableImg = function(id, thumbnail) {
+ var previewing = previewGeneration[id] || new qq.Promise().failure(), notAvailableImgPlacement = new qq.Promise();
+ cachedThumbnailNotAvailableImg.then(function(img) {
+ previewing.then(function() {
+ notAvailableImgPlacement.success();
+ }, function() {
+ maybeScalePlaceholderViaCss(img, thumbnail);
+ thumbnail.onload = function() {
+ thumbnail.onload = null;
+ notAvailableImgPlacement.success();
+ };
+ thumbnail.src = img.src;
+ show(thumbnail);
+ });
+ });
+ return notAvailableImgPlacement;
+ }, parseAndGetTemplate = function() {
+ var scriptEl, scriptHtml, fileListNode, tempTemplateEl, fileListHtml, defaultButton, dropArea, thumbnail, dropProcessing, dropTextEl, uploaderEl;
+ log("Parsing template");
+ if (options.templateIdOrEl == null) {
+ throw new Error("You MUST specify either a template element or ID!");
+ }
+ if (qq.isString(options.templateIdOrEl)) {
+ scriptEl = document.getElementById(options.templateIdOrEl);
+ if (scriptEl === null) {
+ throw new Error(qq.format("Cannot find template script at ID '{}'!", options.templateIdOrEl));
+ }
+ scriptHtml = scriptEl.innerHTML;
+ } else {
+ if (options.templateIdOrEl.innerHTML === undefined) {
+ throw new Error("You have specified an invalid value for the template option! " + "It must be an ID or an Element.");
+ }
+ scriptHtml = options.templateIdOrEl.innerHTML;
+ }
+ scriptHtml = qq.trimStr(scriptHtml);
+ tempTemplateEl = document.createElement("div");
+ tempTemplateEl.appendChild(qq.toElement(scriptHtml));
+ uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);
+ if (options.button) {
+ defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);
+ if (defaultButton) {
+ qq(defaultButton).remove();
+ }
+ }
+ if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {
+ dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);
+ if (dropProcessing) {
+ qq(dropProcessing).remove();
+ }
+ }
+ dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);
+ if (dropArea && !qq.DragAndDrop) {
+ log("DnD module unavailable.", "info");
+ qq(dropArea).remove();
+ }
+ if (!qq.supportedFeatures.fileDrop) {
+ uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);
+ if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {
+ qq(dropArea).css({
+ display: "none"
+ });
+ }
+ } else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {
+ dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);
+ dropTextEl && qq(dropTextEl).remove();
+ }
+ thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);
+ if (!showThumbnails) {
+ thumbnail && qq(thumbnail).remove();
+ } else if (thumbnail) {
+ thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));
+ thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;
+ serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);
+ }
+ showThumbnails = showThumbnails && thumbnail;
+ isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;
+ isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;
+ fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);
+ if (fileListNode == null) {
+ throw new Error("Could not find the file list container in the template!");
+ }
+ fileListHtml = fileListNode.innerHTML;
+ fileListNode.innerHTML = "";
+ if (tempTemplateEl.getElementsByTagName("DIALOG").length) {
+ document.createElement("dialog");
+ }
+ log("Template parsing complete");
+ return {
+ template: qq.trimStr(tempTemplateEl.innerHTML),
+ fileTemplate: qq.trimStr(fileListHtml)
+ };
+ }, prependFile = function(el, index, fileList) {
+ var parentEl = fileList, beforeEl = parentEl.firstChild;
+ if (index > 0) {
+ beforeEl = qq(parentEl).children()[index].nextSibling;
+ }
+ parentEl.insertBefore(el, beforeEl);
+ }, processNewQueuedPreviewRequest = function(queuedThumbRequest) {
+ var id = queuedThumbRequest.id, optFileOrBlob = queuedThumbRequest.optFileOrBlob, relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId, thumbnail = getThumbnail(id), spec = {
+ customResizeFunction: queuedThumbRequest.customResizeFunction,
+ maxSize: thumbnailMaxSize,
+ orient: true,
+ scale: true
+ };
+ if (qq.supportedFeatures.imagePreviews) {
+ if (thumbnail) {
+ if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ } else {
+ displayWaitingImg(thumbnail).done(function() {
+ previewGeneration[id] = new qq.Promise();
+ previewGeneration[id].done(function() {
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ });
+ if (relatedThumbnailId != null) {
+ useCachedPreview(id, relatedThumbnailId);
+ } else {
+ generateNewPreview(id, optFileOrBlob, spec);
+ }
+ });
+ }
+ } else {
+ generateNextQueuedPreview();
+ }
+ } else if (thumbnail) {
+ displayWaitingImg(thumbnail);
+ generateNextQueuedPreview();
+ }
+ }, processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {
+ var id = queuedThumbRequest.id, thumbnailUrl = queuedThumbRequest.thumbnailUrl, showWaitingImg = queuedThumbRequest.showWaitingImg, thumbnail = getThumbnail(id), spec = {
+ customResizeFunction: queuedThumbRequest.customResizeFunction,
+ scale: serverScale,
+ maxSize: thumbnailMaxSize
+ };
+ if (thumbnail) {
+ if (thumbnailUrl) {
+ if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ } else {
+ if (showWaitingImg) {
+ displayWaitingImg(thumbnail);
+ }
+ return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(function() {
+ show(thumbnail);
+ generatedThumbnails++;
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ }, function() {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ });
+ }
+ } else {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ }
+ }
+ }, setProgressBarWidth = function(id, percent) {
+ var bar = getProgress(id), progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;
+ if (bar && !qq(bar).hasClass(progressBarSelector)) {
+ bar = qq(bar).getFirstByClass(progressBarSelector);
+ }
+ if (bar) {
+ qq(bar).css({
+ width: percent + "%"
+ });
+ bar.setAttribute("aria-valuenow", percent);
+ }
+ }, show = function(el) {
+ el && qq(el).removeClass(options.classes.hide);
+ }, useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {
+ var targetThumbnail = getThumbnail(targetThumbnailId), cachedThumbnail = getThumbnail(cachedThumbnailId);
+ log(qq.format("ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));
+ previewGeneration[cachedThumbnailId].then(function() {
+ generatedThumbnails++;
+ previewGeneration[targetThumbnailId].success();
+ log(qq.format("Now using previously generated thumbnail created for ID {} on ID {}.", cachedThumbnailId, targetThumbnailId));
+ targetThumbnail.src = cachedThumbnail.src;
+ show(targetThumbnail);
+ }, function() {
+ previewGeneration[targetThumbnailId].failure();
+ if (!options.placeholders.waitUntilUpdate) {
+ maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);
+ }
+ });
+ };
+ qq.extend(options, spec);
+ log = options.log;
+ if (!qq.supportedFeatures.imagePreviews) {
+ options.limits.timeBetweenThumbs = 0;
+ options.limits.maxThumbs = 0;
+ }
+ container = options.containerEl;
+ showThumbnails = options.imageGenerator !== undefined;
+ templateHtml = parseAndGetTemplate();
+ cacheThumbnailPlaceholders();
+ qq.extend(this, {
+ render: function() {
+ log("Rendering template in DOM.");
+ generatedThumbnails = 0;
+ container.innerHTML = templateHtml.template;
+ hide(getDropProcessing());
+ this.hideTotalProgress();
+ fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);
+ log("Template rendering complete");
+ },
+ renderFailure: function(message) {
+ var cantRenderEl = qq.toElement(message);
+ container.innerHTML = "";
+ container.appendChild(cantRenderEl);
+ },
+ reset: function() {
+ this.render();
+ },
+ clearFiles: function() {
+ fileList.innerHTML = "";
+ },
+ disableCancel: function() {
+ isCancelDisabled = true;
+ },
+ addFile: function(id, name, prependInfo, hideForever, batch) {
+ var fileEl = qq.toElement(templateHtml.fileTemplate), fileNameEl = getTemplateEl(fileEl, selectorClasses.file), uploaderEl = getTemplateEl(container, selectorClasses.uploader), fileContainer = batch ? fileBatch.content : fileList, thumb;
+ if (batch) {
+ fileBatch.map[id] = fileEl;
+ }
+ qq(fileEl).addClass(FILE_CLASS_PREFIX + id);
+ uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);
+ if (fileNameEl) {
+ qq(fileNameEl).setText(name);
+ fileNameEl.setAttribute("title", name);
+ }
+ fileEl.setAttribute(FILE_ID_ATTR, id);
+ if (prependInfo) {
+ prependFile(fileEl, prependInfo.index, fileContainer);
+ } else {
+ fileContainer.appendChild(fileEl);
+ }
+ if (hideForever) {
+ fileEl.style.display = "none";
+ qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);
+ } else {
+ hide(getProgress(id));
+ hide(getSize(id));
+ hide(getDelete(id));
+ hide(getRetry(id));
+ hide(getPause(id));
+ hide(getContinue(id));
+ if (isCancelDisabled) {
+ this.hideCancel(id);
+ }
+ thumb = getThumbnail(id);
+ if (thumb && !thumb.src) {
+ cachedWaitingForThumbnailImg.then(function(waitingImg) {
+ thumb.src = waitingImg.src;
+ if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {
+ qq(thumb).css({
+ maxHeight: waitingImg.style.maxHeight,
+ maxWidth: waitingImg.style.maxWidth
+ });
+ }
+ show(thumb);
+ });
+ }
+ }
+ },
+ addFileToCache: function(id, name, prependInfo, hideForever) {
+ this.addFile(id, name, prependInfo, hideForever, true);
+ },
+ addCacheToDom: function() {
+ fileList.appendChild(fileBatch.content);
+ fileBatch.content = document.createDocumentFragment();
+ fileBatch.map = {};
+ },
+ removeFile: function(id) {
+ qq(getFile(id)).remove();
+ },
+ getFileId: function(el) {
+ var currentNode = el;
+ if (currentNode) {
+ while (currentNode.getAttribute(FILE_ID_ATTR) == null) {
+ currentNode = currentNode.parentNode;
+ }
+ return parseInt(currentNode.getAttribute(FILE_ID_ATTR));
+ }
+ },
+ getFileList: function() {
+ return fileList;
+ },
+ markFilenameEditable: function(id) {
+ var filename = getFilename(id);
+ filename && qq(filename).addClass(options.classes.editable);
+ },
+ updateFilename: function(id, name) {
+ var filenameEl = getFilename(id);
+ if (filenameEl) {
+ qq(filenameEl).setText(name);
+ filenameEl.setAttribute("title", name);
+ }
+ },
+ hideFilename: function(id) {
+ hide(getFilename(id));
+ },
+ showFilename: function(id) {
+ show(getFilename(id));
+ },
+ isFileName: function(el) {
+ return qq(el).hasClass(selectorClasses.file);
+ },
+ getButton: function() {
+ return options.button || getTemplateEl(container, selectorClasses.button);
+ },
+ hideDropProcessing: function() {
+ hide(getDropProcessing());
+ },
+ showDropProcessing: function() {
+ show(getDropProcessing());
+ },
+ getDropZone: function() {
+ return getTemplateEl(container, selectorClasses.drop);
+ },
+ isEditFilenamePossible: function() {
+ return isEditElementsExist;
+ },
+ hideRetry: function(id) {
+ hide(getRetry(id));
+ },
+ isRetryPossible: function() {
+ return isRetryElementExist;
+ },
+ showRetry: function(id) {
+ show(getRetry(id));
+ },
+ getFileContainer: function(id) {
+ return getFile(id);
+ },
+ showEditIcon: function(id) {
+ var icon = getEditIcon(id);
+ icon && qq(icon).addClass(options.classes.editable);
+ },
+ isHiddenForever: function(id) {
+ return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);
+ },
+ hideEditIcon: function(id) {
+ var icon = getEditIcon(id);
+ icon && qq(icon).removeClass(options.classes.editable);
+ },
+ isEditIcon: function(el) {
+ return qq(el).hasClass(selectorClasses.editNameIcon, true);
+ },
+ getEditInput: function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);
+ },
+ isEditInput: function(el) {
+ return qq(el).hasClass(selectorClasses.editFilenameInput, true);
+ },
+ updateProgress: function(id, loaded, total) {
+ var bar = getProgress(id), percent;
+ if (bar && total > 0) {
+ percent = Math.round(loaded / total * 100);
+ if (percent === 100) {
+ hide(bar);
+ } else {
+ show(bar);
+ }
+ setProgressBarWidth(id, percent);
+ }
+ },
+ updateTotalProgress: function(loaded, total) {
+ this.updateProgress(null, loaded, total);
+ },
+ hideProgress: function(id) {
+ var bar = getProgress(id);
+ bar && hide(bar);
+ },
+ hideTotalProgress: function() {
+ this.hideProgress();
+ },
+ resetProgress: function(id) {
+ setProgressBarWidth(id, 0);
+ this.hideTotalProgress(id);
+ },
+ resetTotalProgress: function() {
+ this.resetProgress();
+ },
+ showCancel: function(id) {
+ if (!isCancelDisabled) {
+ var cancel = getCancel(id);
+ cancel && qq(cancel).removeClass(options.classes.hide);
+ }
+ },
+ hideCancel: function(id) {
+ hide(getCancel(id));
+ },
+ isCancel: function(el) {
+ return qq(el).hasClass(selectorClasses.cancel, true);
+ },
+ allowPause: function(id) {
+ show(getPause(id));
+ hide(getContinue(id));
+ },
+ uploadPaused: function(id) {
+ this.setStatusText(id, options.text.paused);
+ this.allowContinueButton(id);
+ hide(getSpinner(id));
+ },
+ hidePause: function(id) {
+ hide(getPause(id));
+ },
+ isPause: function(el) {
+ return qq(el).hasClass(selectorClasses.pause, true);
+ },
+ isContinueButton: function(el) {
+ return qq(el).hasClass(selectorClasses.continueButton, true);
+ },
+ allowContinueButton: function(id) {
+ show(getContinue(id));
+ hide(getPause(id));
+ },
+ uploadContinued: function(id) {
+ this.setStatusText(id, "");
+ this.allowPause(id);
+ show(getSpinner(id));
+ },
+ showDeleteButton: function(id) {
+ show(getDelete(id));
+ },
+ hideDeleteButton: function(id) {
+ hide(getDelete(id));
+ },
+ isDeleteButton: function(el) {
+ return qq(el).hasClass(selectorClasses.deleteButton, true);
+ },
+ isRetry: function(el) {
+ return qq(el).hasClass(selectorClasses.retry, true);
+ },
+ updateSize: function(id, text) {
+ var size = getSize(id);
+ if (size) {
+ show(size);
+ qq(size).setText(text);
+ }
+ },
+ setStatusText: function(id, text) {
+ var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);
+ if (textEl) {
+ if (text == null) {
+ qq(textEl).clearText();
+ } else {
+ qq(textEl).setText(text);
+ }
+ }
+ },
+ hideSpinner: function(id) {
+ qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);
+ hide(getSpinner(id));
+ },
+ showSpinner: function(id) {
+ qq(getFile(id)).addClass(IN_PROGRESS_CLASS);
+ show(getSpinner(id));
+ },
+ generatePreview: function(id, optFileOrBlob, customResizeFunction) {
+ if (!this.isHiddenForever(id)) {
+ thumbGenerationQueue.push({
+ id: id,
+ customResizeFunction: customResizeFunction,
+ optFileOrBlob: optFileOrBlob
+ });
+ !thumbnailQueueMonitorRunning && generateNextQueuedPreview();
+ }
+ },
+ updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {
+ if (!this.isHiddenForever(id)) {
+ thumbGenerationQueue.push({
+ customResizeFunction: customResizeFunction,
+ update: true,
+ id: id,
+ thumbnailUrl: thumbnailUrl,
+ showWaitingImg: showWaitingImg
+ });
+ !thumbnailQueueMonitorRunning && generateNextQueuedPreview();
+ }
+ },
+ hasDialog: function(type) {
+ return qq.supportedFeatures.dialogElement && !!getDialog(type);
+ },
+ showDialog: function(type, message, defaultValue) {
+ var dialog = getDialog(type), messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage), inputEl = dialog.getElementsByTagName("INPUT")[0], cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton), okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton), promise = new qq.Promise(), closeHandler = function() {
+ cancelBtn.removeEventListener("click", cancelClickHandler);
+ okBtn && okBtn.removeEventListener("click", okClickHandler);
+ promise.failure();
+ }, cancelClickHandler = function() {
+ cancelBtn.removeEventListener("click", cancelClickHandler);
+ dialog.close();
+ }, okClickHandler = function() {
+ dialog.removeEventListener("close", closeHandler);
+ okBtn.removeEventListener("click", okClickHandler);
+ dialog.close();
+ promise.success(inputEl && inputEl.value);
+ };
+ dialog.addEventListener("close", closeHandler);
+ cancelBtn.addEventListener("click", cancelClickHandler);
+ okBtn && okBtn.addEventListener("click", okClickHandler);
+ if (inputEl) {
+ inputEl.value = defaultValue;
+ }
+ messageEl.textContent = message;
+ dialog.showModal();
+ return promise;
+ }
+ });
+ };
+ qq.UiEventHandler = function(s, protectedApi) {
+ "use strict";
+ var disposer = new qq.DisposeSupport(), spec = {
+ eventType: "click",
+ attachTo: null,
+ onHandled: function(target, event) {}
+ };
+ qq.extend(this, {
+ addHandler: function(element) {
+ addHandler(element);
+ },
+ dispose: function() {
+ disposer.dispose();
+ }
+ });
+ function addHandler(element) {
+ disposer.attach(element, spec.eventType, function(event) {
+ event = event || window.event;
+ var target = event.target || event.srcElement;
+ spec.onHandled(target, event);
+ });
+ }
+ qq.extend(protectedApi, {
+ getFileIdFromItem: function(item) {
+ return item.qqFileId;
+ },
+ getDisposeSupport: function() {
+ return disposer;
+ }
+ });
+ qq.extend(spec, s);
+ if (spec.attachTo) {
+ addHandler(spec.attachTo);
+ }
+ };
+ qq.FileButtonsClickHandler = function(s) {
+ "use strict";
+ var inheritedInternalApi = {}, spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ onDeleteFile: function(fileId) {},
+ onCancel: function(fileId) {},
+ onRetry: function(fileId) {},
+ onPause: function(fileId) {},
+ onContinue: function(fileId) {},
+ onGetName: function(fileId) {}
+ }, buttonHandlers = {
+ cancel: function(id) {
+ spec.onCancel(id);
+ },
+ retry: function(id) {
+ spec.onRetry(id);
+ },
+ deleteButton: function(id) {
+ spec.onDeleteFile(id);
+ },
+ pause: function(id) {
+ spec.onPause(id);
+ },
+ continueButton: function(id) {
+ spec.onContinue(id);
+ }
+ };
+ function examineEvent(target, event) {
+ qq.each(buttonHandlers, function(buttonType, handler) {
+ var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1), fileId;
+ if (spec.templating["is" + firstLetterCapButtonType](target)) {
+ fileId = spec.templating.getFileId(target);
+ qq.preventDefault(event);
+ spec.log(qq.format("Detected valid file button click event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ handler(fileId);
+ return false;
+ }
+ });
+ }
+ qq.extend(spec, s);
+ spec.eventType = "click";
+ spec.onHandled = examineEvent;
+ spec.attachTo = spec.templating.getFileList();
+ qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameClickHandler = function(s) {
+ "use strict";
+ var inheritedInternalApi = {}, spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ classes: {
+ file: "qq-upload-file",
+ editNameIcon: "qq-edit-filename-icon"
+ },
+ onGetUploadStatus: function(fileId) {},
+ onGetName: function(fileId) {}
+ };
+ qq.extend(spec, s);
+ function examineEvent(target, event) {
+ if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {
+ var fileId = spec.templating.getFileId(target), status = spec.onGetUploadStatus(fileId);
+ if (status === qq.status.SUBMITTED) {
+ spec.log(qq.format("Detected valid filename click event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ qq.preventDefault(event);
+ inheritedInternalApi.handleFilenameEdit(fileId, target, true);
+ }
+ }
+ }
+ spec.eventType = "click";
+ spec.onHandled = examineEvent;
+ qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {
+ "use strict";
+ var spec = {
+ templating: null,
+ onGetUploadStatus: function(fileId) {},
+ log: function(message, lvl) {}
+ };
+ if (!inheritedInternalApi) {
+ inheritedInternalApi = {};
+ }
+ function handleInputFocus(target, event) {
+ if (spec.templating.isEditInput(target)) {
+ var fileId = spec.templating.getFileId(target), status = spec.onGetUploadStatus(fileId);
+ if (status === qq.status.SUBMITTED) {
+ spec.log(qq.format("Detected valid filename input focus event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ inheritedInternalApi.handleFilenameEdit(fileId, target);
+ }
+ }
+ }
+ spec.eventType = "focusin";
+ spec.onHandled = handleInputFocus;
+ qq.extend(spec, s);
+ qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameInputFocusHandler = function(spec) {
+ "use strict";
+ spec.eventType = "focus";
+ spec.attachTo = null;
+ qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));
+ };
+ qq.FilenameEditHandler = function(s, inheritedInternalApi) {
+ "use strict";
+ var spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ onGetUploadStatus: function(fileId) {},
+ onGetName: function(fileId) {},
+ onSetName: function(fileId, newName) {},
+ onEditingStatusChange: function(fileId, isEditing) {}
+ };
+ function getFilenameSansExtension(fileId) {
+ var filenameSansExt = spec.onGetName(fileId), extIdx = filenameSansExt.lastIndexOf(".");
+ if (extIdx > 0) {
+ filenameSansExt = filenameSansExt.substr(0, extIdx);
+ }
+ return filenameSansExt;
+ }
+ function getOriginalExtension(fileId) {
+ var origName = spec.onGetName(fileId);
+ return qq.getExtension(origName);
+ }
+ function handleNameUpdate(newFilenameInputEl, fileId) {
+ var newName = newFilenameInputEl.value, origExtension;
+ if (newName !== undefined && qq.trimStr(newName).length > 0) {
+ origExtension = getOriginalExtension(fileId);
+ if (origExtension !== undefined) {
+ newName = newName + "." + origExtension;
+ }
+ spec.onSetName(fileId, newName);
+ }
+ spec.onEditingStatusChange(fileId, false);
+ }
+ function registerInputBlurHandler(inputEl, fileId) {
+ inheritedInternalApi.getDisposeSupport().attach(inputEl, "blur", function() {
+ handleNameUpdate(inputEl, fileId);
+ });
+ }
+ function registerInputEnterKeyHandler(inputEl, fileId) {
+ inheritedInternalApi.getDisposeSupport().attach(inputEl, "keyup", function(event) {
+ var code = event.keyCode || event.which;
+ if (code === 13) {
+ handleNameUpdate(inputEl, fileId);
+ }
+ });
+ }
+ qq.extend(spec, s);
+ spec.attachTo = spec.templating.getFileList();
+ qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));
+ qq.extend(inheritedInternalApi, {
+ handleFilenameEdit: function(id, target, focusInput) {
+ var newFilenameInputEl = spec.templating.getEditInput(id);
+ spec.onEditingStatusChange(id, true);
+ newFilenameInputEl.value = getFilenameSansExtension(id);
+ if (focusInput) {
+ newFilenameInputEl.focus();
+ }
+ registerInputBlurHandler(newFilenameInputEl, id);
+ registerInputEnterKeyHandler(newFilenameInputEl, id);
+ }
+ });
+ };
+ (function() {
+ "use strict";
+ qq.azure.FineUploader = function(o) {
+ var options = {
+ failedUploadTextDisplay: {
+ mode: "custom"
+ }
+ };
+ qq.extend(options, o, true);
+ qq.FineUploader.call(this, options, "azure");
+ };
+ qq.extend(qq.azure.FineUploader.prototype, qq.azure.FineUploaderBasic.prototype);
+ qq.extend(qq.azure.FineUploader.prototype, qq.uiPublicApi);
+ qq.extend(qq.azure.FineUploader.prototype, qq.uiPrivateApi);
+ qq.extend(qq.azure.FineUploader.prototype, {});
+ })();
+})(window);
+//# sourceMappingURL=azure.jquery.fine-uploader.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.js.map b/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.js.map
new file mode 100644
index 000000000000..91bf4956b27b
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/jquery-plugin.js","../client/js/jquery-dnd.js","../client/js/azure/jquery-plugin.js","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/azure/util.js","../client/js/non-traditional-common/uploader.basic.api.js","../client/js/azure/uploader.basic.js","../client/js/azure/azure.xhr.upload.handler.js","../client/js/azure/get-sas.js","../client/js/uploadsuccess.ajax.requester.js","../client/js/azure/rest/delete-blob.js","../client/js/azure/rest/put-blob.js","../client/js/azure/rest/put-block.js","../client/js/azure/rest/put-block-list.js","../client/js/dnd.js","../client/js/uploader.api.js","../client/js/uploader.js","../client/js/templating.js","../client/js/ui.handler.events.js","../client/js/ui.handler.click.filebuttons.js","../client/js/ui.handler.click.filename.js","../client/js/ui.handler.focusin.filenameinput.js","../client/js/ui.handler.focus.filenameinput.js","../client/js/ui.handler.edit.filename.js","../client/js/azure/uploader.js"],"names":["global","$","$el","pluginOptions","init","options","xformedOpts","transformVariables","newUploaderInstance","getNewUploaderInstance","uploader","addCallbacks","params","uploaderType","pluginOption","namespace","charAt","toUpperCase","slice","toLowerCase","qq","FineUploader","dataStore","key","val","data","undefined","instanceToStore","option","optionVal","transformedOpts","callbacks","each","_options","prop","nonJqueryCallback","name","callbackEventTarget","exec","substring","originalArgs","Array","prototype","call","arguments","transformedArgs","nonJqueryCallbackRetVal","jqueryEventCallbackRetVal","idx","arg","push","maybeWrapInJquery","apply","this","triggerHandler","error","log","message","source","dest","xformed","arrayVals","element","inArray","isPlainObject","isArray","arrayVal","arrayObjDest","merge","isValidCommand","command","type","match","delegateCommand","xformedArgs","origArgs","retVal","transformedVal","nodeType","cloneNode","fn","fineUploader","optionsOrCommand","self","selfArgs","retVals","index","el","length","jQuery","rootDataKey","dropZoneElements","dnd","DragAndDrop","func","$callbackEl","args","jqueryHandlerResult","fineUploaderDnd","fineUploaderAzure","endpointType","hide","style","display","attach","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","getFirstByClass","children","child","firstChild","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","getAttribute","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","createBlob","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","intArray","mimeString","split","indexOf","atob","decodeURI","ArrayBuffer","Uint8Array","character","charCodeAt","level","console","isObject","variable","Object","toString","isFunction","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","newStr","nextIdxToReplace","strBefore","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","override","target","sourceFn","super_","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","Storage","getItem","bind","oldFunc","context","newArgs","concat","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","testSupportsFileInputElement","supported","tempInput","disabled","ex","isChrome21OrHigher","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","disposeSupport","acceptFiles","focusClass","folders","hoverClass","ios8BrowserCrashWorkaround","onChange","title","buttonId","createInput","BUTTON_ID_ATTR_NAME","setMultiple","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","byUuid","byStatus","byProxyGroupId","byBatchId","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","getDataByStatus","status","statusResults","statuses","statusEnum","statusResultIndexes","dataIndex","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","promiseToReturn","fileOrUrl","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","accept","validation","allowedExtensions","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","messages","names","validationBase","extensionsForMessage","placeholderMatch","replacement","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","shouldParamsBeInQueryString","queue","requestData","acceptHeader","validMethods","contentType","mandatedParams","allowXRequestedWithAndCacheControl","successfulResponseCodes","DELETE","PATCH","POST","PUT","GET","onSend","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","dequeue","nextId","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","optXhr","payload","url","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","setRequestHeader","responseCode","prepareToSend","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","controller","chunkingPossible","concurrentChunkingPossible","preventRetryResponse","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","responseToReport","inProgressIdx","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","formHandlerInstanceId","onloadCallbacks","detachLoadEvents","postMessageCallbackTimers","isCors","corsMessageReceiver","expungeFile","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","_parseJsonResponse","onloadCallback","_detachLoadEvent","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","chunkFiles","resumeEnabled","xhrId","ajaxRequester","_getAjaxRequester","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","requester","getMandatedParams","_method","detectSubsampling","img","iw","naturalWidth","ih","naturalHeight","ctx","width","getContext","drawImage","getImageData","detectVerticalSquash","sy","ey","py","alpha","ratio","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","d","tmpCanvas","vertSquashRatio","dw","dh","dy","tmpCtx","sx","dx","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","imgWidth","imgHeight","opt","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetAnchor","targetProtocol","targetHostname","targetPort","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","rendered","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","TAG_IDS","TAG_INFO","274","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","vals","idHex","tagsToFindIdx","tagValHex","tagValLength","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","output","chr1","chr2","chr3","enc1","enc2","enc3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","detachPasteHandler","isImage","registerPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","formEl","_form2Obj","determineNewEndpoint","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","azure","util","AZURE_PARAM_PREFIX","_paramNameMatchesAzureParameter","_getPrefixedParamName","getParamsAsHeaders","headerName","parseAzureError","domParser","DOMParser","responseDoc","parseFromString","errorTag","errorDetails","codeTag","messageTag","nonTraditionalBasePublicApi","setUploadSuccessParams","_uploadSuccessParamsStore","setUploadSuccessEndpoint","_uploadSuccessEndpointStore","nonTraditionalBasePrivateApi","onCompleteArgs","successEndpoint","successCustomHeaders","uploadSuccess","successMethod","uploadSuccessParams","fileParams","onSuccessFromServer","successRequestResult","_failedSuccessRequestCallbacks","onFailureFromServer","submitSuccessRequest","successAjaxRequester","UploadSuccessAjaxRequester","_getEndpointSpecificParams","sendSuccessRequest","successRequestCallback","signature","blobProperties","minFileSize","_cannedBlobNames","getBlobName","onGetBlobName","_determineBlobName","deleteBlob","_deleteBlob","blobNameOptionValue","fileExtension","blobNameToUse","blobName","relatedToCancel","deleteBlobSasUri","blobUriStore","deleteFileEndpointStore","getSasSuccess","sasUri","getSasFailure","DeleteBlob","getSas","GetSas","restRequestVerb","minFileSizeForChunking","getBlobMetadata","putBlob","PutBlob","putBlock","PutBlock","putBlockList","PutBlockList","getSasForPutBlobOrBlock","combineChunks","getSignedUrl","mimeType","blockIdEntries","determineBlobUrl","containerUrl","getBlobNameSuccess","getBlobNameFailure","getSasId","getSasXhr","determineBlobUrlSuccess","blobUrl","determineBlobUrlFailure","azureError","blockIdEntry","chunkingData","maybePossible","requestPromises","sasResponseReceived","blobUri","requestPromise","restVerb","bloburi","pendingRequests","handleSuccessResponse","responseJson","successIndicator","failureIndicator","parsedResponse","codes","endpoints","promises","endpointHandler","Content-Type","createBlockId","partNum","digits","zeros","paddedPartNum","btoa","blockId","createRequestBody","doc","implementation","createDocument","latestEl","latestTextEl","createTextNode","XMLSerializer","serializeToString","fileMimeType","registerXhrCallback","blockIdsXml","x-ms-blob-content-type","HIDE_ZONES_EVENT_NAME","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","droppedFiles","allowMultipleItems","dropActive","uploadDroppedFiles","uploadDropZone","filesAsArray","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","parseEntryPromise","fullPath","indexOfNameInFullPath","qqPath","fileError","isDirectory","getFilesInDirectory","allEntriesRead","entriesLeft","readFailure","accumEntries","existingPromise","dirReader","createReader","readEntries","readSuccess","newEntries","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","dropError","setupDropzone","dropArea","dropZone","UploadDropZone","onEnter","stopPropagation","onLeaveNotDescendants","onDrop","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","relatedTarget","y","setupDragDrop","dropZones","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","targetEl","errorSpecifics","preventDrop","dropOutsideDisabled","dragoverShouldBeCanceled","disableDropOutside","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","isOrSetDropDisabled","isDisabled","triggerHidezonesEvent","hideZonesEvent","triggerUsingOldApi","createEvent","initEvent","CustomEvent","dispatchEvent","attachEvents","effect","elementFromPoint","clientX","clientY","uiPublicApi","_parent","_templating","addCacheToDom","clearFiles","addExtraDropzone","_dnd","removeExtraDropzone","getItemByFileId","isHiddenForever","getFileContainer","_setupDragAndDrop","_totalFilesInBatch","_filesInBatchAddedToUi","_setupClickAndEditEventHandlers","formattedFilename","updateFilename","uploadPaused","continued","uploadContinued","getId","fileContainerOrChildEl","getFileId","getDropTarget","qqDropTarget","uiPrivateApi","_removeFileItem","removeFile","_fileButtonsClickHandler","FileButtonsClickHandler","_bindFileButtonsClickEvent","_focusinEventSupported","_isEditFilenameEnabled","_filenameClickHandler","_bindFilenameClickEvent","_filenameInputFocusInHandler","_bindFilenameInputFocusInEvent","_filenameInputFocusHandler","_bindFilenameInputFocusEvent","dragAndDrop","extraDropzones","templating","defaultDropZone","getDropZone","showDropProcessing","hideDropProcessing","errorData","lvl","onDeleteFile","onRetry","onPause","onContinue","onGetName","isEditFilenamePossible","FilenameClickHandler","FilenameInputFocusHandler","_filenameEditHandler","onGetUploadStatus","onSetName","onEditingStatusChange","isEditing","qqInput","getEditInput","qqFileContainer","hideFilename","hideEditIcon","showFilename","showEditIcon","markFilenameEditable","hideRetry","setStatusText","_classes","retrying","hidePause","FilenameInputFocusInHandler","hideSpinner","resetTotalProgress","reportDirectoryPaths","qqpath","_addToList","addHandler","updateProgress","hideCancel","hideProgress","waitingForResponse","_displayFileSize","parentRetVal","completeUpload","_markFileAsSuccessful","fail","showCancel","isRetryPossible","showRetry","_controlFailureTextDisplay","newResult","showDeleteButton","_maybeUpdateThumbnail","showSpinner","allowPause","retryNumForDisplay","maxAuto","retryNote","_showCancelLink","showAutoRetryNote","autoRetryNote","resetProgress","_onSubmitDeleteSuccess","forceConfirm","_showDeleteConfirm","_sendDeleteRequest","deletingFailedText","hideDeleteButton","deletingStatusText","confirmMessage","deleteRequestArgs","showConfirm","canned","prependData","prependIndex","dontDisplay","hideScaled","prependFiles","disableCancel","_handledProxyGroup","_clearList","addFileToCache","updateThumbnail","thumbnails","generatePreview","fileSizeOnSubmit","loadedSize","sizeForDisplay","_formatProgress","uploadedSize","formatProgress","mode","responseProperty","failureReason","failedUploadTextDisplay","failUpload","enableTooltip","_showTooltip","showMessage","_setupPastePrompt","namePromptMessage","defaultVal","showPrompt","fileStatus","placeholders","waitUntilResponse","listElement","template","editable","tooManyFilesError","unsupportedBrowser","promptForName","maxCount","notAvailablePath","waitingPath","timeBetweenThumbs","hasDialog","showDialog","confirm","defaultValue","prompt","Templating","templateIdOrEl","containerEl","fileContainerEl","maxThumbs","waitUntilUpdate","thumbnailNotAvailable","waitingForThumbnail","renderFailure","FILE_ID_ATTR","FILE_CLASS_PREFIX","THUMBNAIL_MAX_SIZE_ATTR","THUMBNAIL_SERVER_SCALE_ATTR","HIDE_DROPZONE_ATTR","DROPZPONE_TEXT_ATTR","IN_PROGRESS_CLASS","HIDDEN_FOREVER_CLASS","fileBatch","content","createDocumentFragment","map","isCancelDisabled","generatedThumbnails","thumbnailQueueMonitorRunning","thumbGenerationQueue","thumbnailMaxSize","selectorClasses","alertDialog","dialogCancelButton","confirmDialog","dialogMessage","dialogOkButton","promptDialog","drop","list","progressBarContainer","totalProgressBarContainer","totalProgressBar","spinner","continueButton","deleteButton","statusText","editFilenameInput","editNameIcon","dropText","dropProcessing","dropProcessingSpinner","thumbnail","previewGeneration","cachedThumbnailNotAvailableImg","cachedWaitingForThumbnailImg","isEditElementsExist","isRetryElementExist","templateHtml","showThumbnails","serverScale","cacheThumbnailPlaceholders","notAvailableUrl","waitingUrl","updatedImg","displayWaitingImg","waitingImgPlacement","maybeScalePlaceholderViaCss","show","generateNewPreview","getThumbnail","qqThumbnailId","maybeSetDisplayNotAvailableImg","generateNextQueuedPreview","queuedThumbRequest","update","processUpdateQueuedPreviewRequest","processNewQueuedPreviewRequest","getCancel","getTemplateEl","getContinue","getDialog","getDelete","getDropProcessing","getEditIcon","getPause","getProgress","getRetry","getSpinner","cssClass","previewing","notAvailableImgPlacement","parseAndGetTemplate","scriptEl","scriptHtml","fileListNode","tempTemplateEl","fileListHtml","defaultButton","dropTextEl","uploaderEl","fileTemplate","prependFile","parentEl","beforeEl","optFileOrBlob","relatedThumbnailId","useCachedPreview","showWaitingImg","setProgressBarWidth","percent","bar","progressBarSelector","targetThumbnailId","cachedThumbnailId","targetThumbnail","cachedThumbnail","hideTotalProgress","cantRenderEl","prependInfo","hideForever","batch","fileEl","fileNameEl","thumb","waitingImg","currentNode","getFileList","filenameEl","isFileName","icon","isEditIcon","isEditInput","isCancel","allowContinueButton","isPause","isContinueButton","isDeleteButton","isRetry","textEl","dialog","messageEl","inputEl","cancelBtn","okBtn","closeHandler","cancelClickHandler","okClickHandler","close","showModal","UiEventHandler","s","protectedApi","eventType","attachTo","onHandled","srcElement","getFileIdFromItem","qqFileId","getDisposeSupport","inheritedInternalApi","buttonHandlers","examineEvent","buttonType","firstLetterCapButtonType","handleFilenameEdit","FilenameEditHandler","handleInputFocus","getFilenameSansExtension","filenameSansExt","getOriginalExtension","origName","handleNameUpdate","newFilenameInputEl","origExtension","registerInputBlurHandler","registerInputEnterKeyHandler","keyCode","which","focusInput","focus"],"mappings":"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","file":"azure.jquery.fine-uploader.js","sourcesContent":[null,"/*globals jQuery, qq*/\n(function($) {\n \"use strict\";\n var $el,\n pluginOptions = [\"uploaderType\", \"endpointType\"];\n\n function init(options) {\n var xformedOpts = transformVariables(options || {}),\n newUploaderInstance = getNewUploaderInstance(xformedOpts);\n\n uploader(newUploaderInstance);\n addCallbacks(xformedOpts, newUploaderInstance);\n\n return $el;\n }\n\n function getNewUploaderInstance(params) {\n var uploaderType = pluginOption(\"uploaderType\"),\n namespace = pluginOption(\"endpointType\");\n\n // If the integrator has defined a specific type of uploader to load, use that, otherwise assume `qq.FineUploader`\n if (uploaderType) {\n // We can determine the correct constructor function to invoke by combining \"FineUploader\"\n // with the upper camel cased `uploaderType` value.\n uploaderType = uploaderType.charAt(0).toUpperCase() + uploaderType.slice(1).toLowerCase();\n\n if (namespace) {\n return new qq[namespace][\"FineUploader\" + uploaderType](params);\n }\n\n return new qq[\"FineUploader\" + uploaderType](params);\n }\n else {\n if (namespace) {\n return new qq[namespace].FineUploader(params);\n }\n\n return new qq.FineUploader(params);\n }\n }\n\n function dataStore(key, val) {\n var data = $el.data(\"fineuploader\");\n\n if (val) {\n if (data === undefined) {\n data = {};\n }\n data[key] = val;\n $el.data(\"fineuploader\", data);\n }\n else {\n if (data === undefined) {\n return null;\n }\n return data[key];\n }\n }\n\n //the underlying Fine Uploader instance is stored in jQuery's data stored, associated with the element\n // tied to this instance of the plug-in\n function uploader(instanceToStore) {\n return dataStore(\"uploader\", instanceToStore);\n }\n\n function pluginOption(option, optionVal) {\n return dataStore(option, optionVal);\n }\n\n // Implement all callbacks defined in Fine Uploader as functions that trigger appropriately names events and\n // return the result of executing the bound handler back to Fine Uploader\n function addCallbacks(transformedOpts, newUploaderInstance) {\n var callbacks = transformedOpts.callbacks = {};\n\n $.each(newUploaderInstance._options.callbacks, function(prop, nonJqueryCallback) {\n var name, callbackEventTarget;\n\n name = /^on(\\w+)/.exec(prop)[1];\n name = name.substring(0, 1).toLowerCase() + name.substring(1);\n callbackEventTarget = $el;\n\n callbacks[prop] = function() {\n var originalArgs = Array.prototype.slice.call(arguments),\n transformedArgs = [],\n nonJqueryCallbackRetVal, jqueryEventCallbackRetVal;\n\n $.each(originalArgs, function(idx, arg) {\n transformedArgs.push(maybeWrapInJquery(arg));\n });\n\n nonJqueryCallbackRetVal = nonJqueryCallback.apply(this, originalArgs);\n\n try {\n jqueryEventCallbackRetVal = callbackEventTarget.triggerHandler(name, transformedArgs);\n }\n catch (error) {\n qq.log(\"Caught error in Fine Uploader jQuery event handler: \" + error.message, \"error\");\n }\n\n /*jshint -W116*/\n if (nonJqueryCallbackRetVal != null) {\n return nonJqueryCallbackRetVal;\n }\n return jqueryEventCallbackRetVal;\n };\n });\n\n newUploaderInstance._options.callbacks = callbacks;\n }\n\n //transform jQuery objects into HTMLElements, and pass along all other option properties\n function transformVariables(source, dest) {\n var xformed, arrayVals;\n\n if (dest === undefined) {\n if (source.uploaderType !== \"basic\") {\n xformed = { element: $el[0] };\n }\n else {\n xformed = {};\n }\n }\n else {\n xformed = dest;\n }\n\n $.each(source, function(prop, val) {\n if ($.inArray(prop, pluginOptions) >= 0) {\n pluginOption(prop, val);\n }\n else if (val instanceof $) {\n xformed[prop] = val[0];\n }\n else if ($.isPlainObject(val)) {\n xformed[prop] = {};\n transformVariables(val, xformed[prop]);\n }\n else if ($.isArray(val)) {\n arrayVals = [];\n $.each(val, function(idx, arrayVal) {\n var arrayObjDest = {};\n\n if (arrayVal instanceof $) {\n $.merge(arrayVals, arrayVal);\n }\n else if ($.isPlainObject(arrayVal)) {\n transformVariables(arrayVal, arrayObjDest);\n arrayVals.push(arrayObjDest);\n }\n else {\n arrayVals.push(arrayVal);\n }\n });\n xformed[prop] = arrayVals;\n }\n else {\n xformed[prop] = val;\n }\n });\n\n if (dest === undefined) {\n return xformed;\n }\n }\n\n function isValidCommand(command) {\n return $.type(command) === \"string\" &&\n !command.match(/^_/) && //enforce private methods convention\n uploader()[command] !== undefined;\n }\n\n // Assuming we have already verified that this is a valid command, call the associated function in the underlying\n // Fine Uploader instance (passing along the arguments from the caller) and return the result of the call back to the caller\n function delegateCommand(command) {\n var xformedArgs = [],\n origArgs = Array.prototype.slice.call(arguments, 1),\n retVal;\n\n transformVariables(origArgs, xformedArgs);\n\n retVal = uploader()[command].apply(uploader(), xformedArgs);\n\n return maybeWrapInJquery(retVal);\n }\n\n // If the value is an `HTMLElement` or `HTMLDocument`, wrap it in a `jQuery` object\n function maybeWrapInJquery(val) {\n var transformedVal = val;\n\n // If the command is returning an `HTMLElement` or `HTMLDocument`, wrap it in a `jQuery` object\n /*jshint -W116*/\n if (val != null && typeof val === \"object\" &&\n (val.nodeType === 1 || val.nodeType === 9) && val.cloneNode) {\n\n transformedVal = $(val);\n }\n\n return transformedVal;\n }\n\n $.fn.fineUploader = function(optionsOrCommand) {\n var self = this, selfArgs = arguments, retVals = [];\n\n this.each(function(index, el) {\n $el = $(el);\n\n if (uploader() && isValidCommand(optionsOrCommand)) {\n retVals.push(delegateCommand.apply(self, selfArgs));\n\n if (self.length === 1) {\n return false;\n }\n }\n else if (typeof optionsOrCommand === \"object\" || !optionsOrCommand) {\n init.apply(self, selfArgs);\n }\n else {\n $.error(\"Method \" + optionsOrCommand + \" does not exist on jQuery.fineUploader\");\n }\n });\n\n if (retVals.length === 1) {\n return retVals[0];\n }\n else if (retVals.length > 1) {\n return retVals;\n }\n\n return this;\n };\n\n}(jQuery));\n","/*globals jQuery, qq*/\n(function($) {\n \"use strict\";\n var rootDataKey = \"fineUploaderDnd\",\n $el;\n\n function init(options) {\n if (!options) {\n options = {};\n }\n\n options.dropZoneElements = [$el];\n var xformedOpts = transformVariables(options);\n addCallbacks(xformedOpts);\n dnd(new qq.DragAndDrop(xformedOpts));\n\n return $el;\n }\n\n function dataStore(key, val) {\n var data = $el.data(rootDataKey);\n\n if (val) {\n if (data === undefined) {\n data = {};\n }\n data[key] = val;\n $el.data(rootDataKey, data);\n }\n else {\n if (data === undefined) {\n return null;\n }\n return data[key];\n }\n }\n\n function dnd(instanceToStore) {\n return dataStore(\"dndInstance\", instanceToStore);\n }\n\n function addCallbacks(transformedOpts) {\n var callbacks = transformedOpts.callbacks = {};\n\n $.each(new qq.DragAndDrop.callbacks(), function(prop, func) {\n var name = prop,\n $callbackEl;\n\n $callbackEl = $el;\n\n callbacks[prop] = function() {\n var args = Array.prototype.slice.call(arguments),\n jqueryHandlerResult = $callbackEl.triggerHandler(name, args);\n\n return jqueryHandlerResult;\n };\n });\n }\n\n //transform jQuery objects into HTMLElements, and pass along all other option properties\n function transformVariables(source, dest) {\n var xformed, arrayVals;\n\n if (dest === undefined) {\n xformed = {};\n }\n else {\n xformed = dest;\n }\n\n $.each(source, function(prop, val) {\n if (val instanceof $) {\n xformed[prop] = val[0];\n }\n else if ($.isPlainObject(val)) {\n xformed[prop] = {};\n transformVariables(val, xformed[prop]);\n }\n else if ($.isArray(val)) {\n arrayVals = [];\n $.each(val, function(idx, arrayVal) {\n if (arrayVal instanceof $) {\n $.merge(arrayVals, arrayVal);\n }\n else {\n arrayVals.push(arrayVal);\n }\n });\n xformed[prop] = arrayVals;\n }\n else {\n xformed[prop] = val;\n }\n });\n\n if (dest === undefined) {\n return xformed;\n }\n }\n\n function isValidCommand(command) {\n return $.type(command) === \"string\" &&\n command === \"dispose\" &&\n dnd()[command] !== undefined;\n }\n\n function delegateCommand(command) {\n var xformedArgs = [], origArgs = Array.prototype.slice.call(arguments, 1);\n transformVariables(origArgs, xformedArgs);\n return dnd()[command].apply(dnd(), xformedArgs);\n }\n\n $.fn.fineUploaderDnd = function(optionsOrCommand) {\n var self = this, selfArgs = arguments, retVals = [];\n\n this.each(function(index, el) {\n $el = $(el);\n\n if (dnd() && isValidCommand(optionsOrCommand)) {\n retVals.push(delegateCommand.apply(self, selfArgs));\n\n if (self.length === 1) {\n return false;\n }\n }\n else if (typeof optionsOrCommand === \"object\" || !optionsOrCommand) {\n init.apply(self, selfArgs);\n }\n else {\n $.error(\"Method \" + optionsOrCommand + \" does not exist in Fine Uploader's DnD module.\");\n }\n });\n\n if (retVals.length === 1) {\n return retVals[0];\n }\n else if (retVals.length > 1) {\n return retVals;\n }\n\n return this;\n };\n\n}(jQuery));\n","/*globals jQuery*/\n/**\n * Simply an alias for the `fineUploader` plug-in wrapper, but hides the required `endpointType` option from the\n * integrator. I thought it may be confusing to convey to the integrator that, when using Fine Uploader in Azure mode,\n * you need to specify an `endpointType` with a value of \"azure\", and perhaps an `uploaderType` with a value of \"basic\" if\n * you want to use basic mode when uploading directly to Azure as well. So, you can use this plug-in alias and not worry\n * about the `endpointType` option at all.\n */\n(function($) {\n \"use strict\";\n\n $.fn.fineUploaderAzure = function(optionsOrCommand) {\n if (typeof optionsOrCommand === \"object\") {\n\n // This option is used to tell the plug-in wrapper to instantiate the appropriate Azure-namespace modules.\n optionsOrCommand.endpointType = \"azure\";\n }\n\n return $.fn.fineUploader.apply(this, arguments);\n };\n\n}(jQuery));\n","/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\"\"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n","/*globals qq, document, CustomEvent*/\nqq.DragAndDrop = function(o) {\n \"use strict\";\n\n var options,\n HIDE_ZONES_EVENT_NAME = \"qq-hidezones\",\n HIDE_BEFORE_ENTER_ATTR = \"qq-hide-dropzone\",\n uploadDropZones = [],\n droppedFiles = [],\n disposeSupport = new qq.DisposeSupport();\n\n options = {\n dropZoneElements: [],\n allowMultipleItems: true,\n classes: {\n dropActive: null\n },\n callbacks: new qq.DragAndDrop.callbacks()\n };\n\n qq.extend(options, o, true);\n\n function uploadDroppedFiles(files, uploadDropZone) {\n // We need to convert the `FileList` to an actual `Array` to avoid iteration issues\n var filesAsArray = Array.prototype.slice.call(files);\n\n options.callbacks.dropLog(\"Grabbed \" + files.length + \" dropped files.\");\n uploadDropZone.dropDisabled(false);\n options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());\n }\n\n function traverseFileTree(entry) {\n var parseEntryPromise = new qq.Promise();\n\n if (entry.isFile) {\n entry.file(function(file) {\n var name = entry.name,\n fullPath = entry.fullPath,\n indexOfNameInFullPath = fullPath.indexOf(name);\n\n // remove file name from full path string\n fullPath = fullPath.substr(0, indexOfNameInFullPath);\n\n // remove leading slash in full path string\n if (fullPath.charAt(0) === \"/\") {\n fullPath = fullPath.substr(1);\n }\n\n file.qqPath = fullPath;\n droppedFiles.push(file);\n parseEntryPromise.success();\n },\n function(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n });\n }\n else if (entry.isDirectory) {\n getFilesInDirectory(entry).then(\n function allEntriesRead(entries) {\n var entriesLeft = entries.length;\n\n qq.each(entries, function(idx, entry) {\n traverseFileTree(entry).done(function() {\n entriesLeft -= 1;\n\n if (entriesLeft === 0) {\n parseEntryPromise.success();\n }\n });\n });\n\n if (!entries.length) {\n parseEntryPromise.success();\n }\n },\n\n function readFailure(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n }\n );\n }\n\n return parseEntryPromise;\n }\n\n // Promissory. Guaranteed to read all files in the root of the passed directory.\n function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {\n var promise = existingPromise || new qq.Promise(),\n dirReader = reader || entry.createReader();\n\n dirReader.readEntries(\n function readSuccess(entries) {\n var newEntries = accumEntries ? accumEntries.concat(entries) : entries;\n\n if (entries.length) {\n setTimeout(function() { // prevent stack overflow, however unlikely\n getFilesInDirectory(entry, dirReader, newEntries, promise);\n }, 0);\n }\n else {\n promise.success(newEntries);\n }\n },\n\n promise.failure\n );\n\n return promise;\n }\n\n function handleDataTransfer(dataTransfer, uploadDropZone) {\n var pendingFolderPromises = [],\n handleDataTransferPromise = new qq.Promise();\n\n options.callbacks.processingDroppedFiles();\n uploadDropZone.dropDisabled(true);\n\n if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.firefox()) {\n return !e.relatedTarget;\n }\n\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n e.preventDefault();\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n // dt.types.contains check is for firefox\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains(\"Files\")));\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n};\n","/*globals qq */\n/**\n * Defines the public API for FineUploader mode.\n */\n(function() {\n \"use strict\";\n\n qq.uiPublicApi = {\n addInitialFiles: function(cannedFileList) {\n this._parent.prototype.addInitialFiles.apply(this, arguments);\n this._templating.addCacheToDom();\n },\n\n clearStoredFiles: function() {\n this._parent.prototype.clearStoredFiles.apply(this, arguments);\n this._templating.clearFiles();\n },\n\n addExtraDropzone: function(element) {\n this._dnd && this._dnd.setupExtraDropzone(element);\n },\n\n removeExtraDropzone: function(element) {\n if (this._dnd) {\n return this._dnd.removeDropzone(element);\n }\n },\n\n getItemByFileId: function(id) {\n if (!this._templating.isHiddenForever(id)) {\n return this._templating.getFileContainer(id);\n }\n },\n\n reset: function() {\n this._parent.prototype.reset.apply(this, arguments);\n this._templating.reset();\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n if (this._dnd) {\n this._dnd.dispose();\n this._dnd = this._setupDragAndDrop();\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n\n this._setupClickAndEditEventHandlers();\n },\n\n setName: function(id, newName) {\n var formattedFilename = this._options.formatFileName(newName);\n\n this._parent.prototype.setName.apply(this, arguments);\n this._templating.updateFilename(id, formattedFilename);\n },\n\n pauseUpload: function(id) {\n var paused = this._parent.prototype.pauseUpload.apply(this, arguments);\n\n paused && this._templating.uploadPaused(id);\n return paused;\n },\n\n continueUpload: function(id) {\n var continued = this._parent.prototype.continueUpload.apply(this, arguments);\n\n continued && this._templating.uploadContinued(id);\n return continued;\n },\n\n getId: function(fileContainerOrChildEl) {\n return this._templating.getFileId(fileContainerOrChildEl);\n },\n\n getDropTarget: function(fileId) {\n var file = this.getFile(fileId);\n\n return file.qqDropTarget;\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploader mode.\n */\n qq.uiPrivateApi = {\n _getButton: function(buttonId) {\n var button = this._parent.prototype._getButton.apply(this, arguments);\n\n if (!button) {\n if (buttonId === this._defaultButtonId) {\n button = this._templating.getButton();\n }\n }\n\n return button;\n },\n\n _removeFileItem: function(fileId) {\n this._templating.removeFile(fileId);\n },\n\n _setupClickAndEditEventHandlers: function() {\n this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();\n\n // A better approach would be to check specifically for focusin event support by querying the DOM API,\n // but the DOMFocusIn event is not exposed as a property, so we have to resort to UA string sniffing.\n this._focusinEventSupported = !qq.firefox();\n\n if (this._isEditFilenameEnabled())\n {\n this._filenameClickHandler = this._bindFilenameClickEvent();\n this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();\n this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();\n }\n },\n\n _setupDragAndDrop: function() {\n var self = this,\n dropZoneElements = this._options.dragAndDrop.extraDropzones,\n templating = this._templating,\n defaultDropZone = templating.getDropZone();\n\n defaultDropZone && dropZoneElements.push(defaultDropZone);\n\n return new qq.DragAndDrop({\n dropZoneElements: dropZoneElements,\n allowMultipleItems: this._options.multiple,\n classes: {\n dropActive: this._options.classes.dropActive\n },\n callbacks: {\n processingDroppedFiles: function() {\n templating.showDropProcessing();\n },\n processingDroppedFilesComplete: function(files, targetEl) {\n templating.hideDropProcessing();\n\n qq.each(files, function(idx, file) {\n file.qqDropTarget = targetEl;\n });\n\n if (files.length) {\n self.addFiles(files, null, null);\n }\n },\n dropError: function(code, errorData) {\n self._itemError(code, errorData);\n },\n dropLog: function(message, level) {\n self.log(message, level);\n }\n }\n });\n },\n\n _bindFileButtonsClickEvent: function() {\n var self = this;\n\n return new qq.FileButtonsClickHandler({\n templating: this._templating,\n\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n\n onDeleteFile: function(fileId) {\n self.deleteFile(fileId);\n },\n\n onCancel: function(fileId) {\n self.cancel(fileId);\n },\n\n onRetry: function(fileId) {\n self.retry(fileId);\n },\n\n onPause: function(fileId) {\n self.pauseUpload(fileId);\n },\n\n onContinue: function(fileId) {\n self.continueUpload(fileId);\n },\n\n onGetName: function(fileId) {\n return self.getName(fileId);\n }\n });\n },\n\n _isEditFilenameEnabled: function() {\n /*jshint -W014 */\n return this._templating.isEditFilenamePossible()\n && !this._options.autoUpload\n && qq.FilenameClickHandler\n && qq.FilenameInputFocusHandler\n && qq.FilenameInputFocusHandler;\n },\n\n _filenameEditHandler: function() {\n var self = this,\n templating = this._templating;\n\n return {\n templating: templating,\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n onGetUploadStatus: function(fileId) {\n return self.getUploads({id: fileId}).status;\n },\n onGetName: function(fileId) {\n return self.getName(fileId);\n },\n onSetName: function(id, newName) {\n self.setName(id, newName);\n },\n onEditingStatusChange: function(id, isEditing) {\n var qqInput = qq(templating.getEditInput(id)),\n qqFileContainer = qq(templating.getFileContainer(id));\n\n if (isEditing) {\n qqInput.addClass(\"qq-editing\");\n templating.hideFilename(id);\n templating.hideEditIcon(id);\n }\n else {\n qqInput.removeClass(\"qq-editing\");\n templating.showFilename(id);\n templating.showEditIcon(id);\n }\n\n // Force IE8 and older to repaint\n qqFileContainer.addClass(\"qq-temp\").removeClass(\"qq-temp\");\n }\n };\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n this._parent.prototype._onUploadStatusChange.apply(this, arguments);\n\n if (this._isEditFilenameEnabled()) {\n // Status for a file exists before it has been added to the DOM, so we must be careful here.\n if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {\n this._templating.markFilenameEditable(id);\n this._templating.hideEditIcon(id);\n }\n }\n\n if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {\n this._templating.hideRetry(id);\n this._templating.setStatusText(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);\n }\n else if (newStatus === qq.status.UPLOAD_FAILED) {\n this._templating.hidePause(id);\n }\n },\n\n _bindFilenameInputFocusInEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusInHandler(spec);\n },\n\n _bindFilenameInputFocusEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusHandler(spec);\n },\n\n _bindFilenameClickEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameClickHandler(spec);\n },\n\n _storeForLater: function(id) {\n this._parent.prototype._storeForLater.apply(this, arguments);\n this._templating.hideSpinner(id);\n },\n\n _onAllComplete: function(successful, failed) {\n this._parent.prototype._onAllComplete.apply(this, arguments);\n this._templating.resetTotalProgress();\n },\n\n _onSubmit: function(id, name) {\n var file = this.getFile(id);\n\n if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {\n this._paramsStore.addReadOnly(id, {\n qqpath: file.qqPath\n });\n }\n\n this._parent.prototype._onSubmit.apply(this, arguments);\n this._addToList(id, name);\n },\n\n // The file item has been added to the DOM.\n _onSubmitted: function(id) {\n // If the edit filename feature is enabled, mark the filename element as \"editable\" and the associated edit icon\n if (this._isEditFilenameEnabled()) {\n this._templating.markFilenameEditable(id);\n this._templating.showEditIcon(id);\n\n // If the focusin event is not supported, we must add a focus handler to the newly create edit filename text input\n if (!this._focusinEventSupported) {\n this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));\n }\n }\n },\n\n // Update the progress bar & percentage as the file is uploaded\n _onProgress: function(id, name, loaded, total) {\n this._parent.prototype._onProgress.apply(this, arguments);\n\n this._templating.updateProgress(id, loaded, total);\n\n if (total === 0 || Math.round(loaded / total * 100) === 100) {\n this._templating.hideCancel(id);\n this._templating.hidePause(id);\n this._templating.hideProgress(id);\n this._templating.setStatusText(id, this._options.text.waitingForResponse);\n\n // If ~last byte was sent, display total file size\n this._displayFileSize(id);\n }\n else {\n // If still uploading, display percentage - total size is actually the total request(s) size\n this._displayFileSize(id, loaded, total);\n }\n },\n\n _onTotalProgress: function(loaded, total) {\n this._parent.prototype._onTotalProgress.apply(this, arguments);\n this._templating.updateTotalProgress(loaded, total);\n },\n\n _onComplete: function(id, name, result, xhr) {\n var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments),\n templating = this._templating,\n fileContainer = templating.getFileContainer(id),\n self = this;\n\n function completeUpload(result) {\n // If this file is not represented in the templating module, perhaps it was hidden intentionally.\n // If so, don't perform any UI-related tasks related to this file.\n if (!fileContainer) {\n return;\n }\n\n templating.setStatusText(id);\n\n qq(fileContainer).removeClass(self._classes.retrying);\n templating.hideProgress(id);\n\n if (self.getUploads({id: id}).status !== qq.status.UPLOAD_FAILED) {\n templating.hideCancel(id);\n }\n templating.hideSpinner(id);\n\n if (result.success) {\n self._markFileAsSuccessful(id);\n }\n else {\n qq(fileContainer).addClass(self._classes.fail);\n templating.showCancel(id);\n\n if (templating.isRetryPossible() && !self._preventRetries[id]) {\n qq(fileContainer).addClass(self._classes.retryable);\n templating.showRetry(id);\n }\n self._controlFailureTextDisplay(id, result);\n }\n }\n\n // The parent may need to perform some async operation before we can accurately determine the status of the upload.\n if (parentRetVal instanceof qq.Promise) {\n parentRetVal.done(function(newResult) {\n completeUpload(newResult);\n });\n\n }\n else {\n completeUpload(result);\n }\n\n return parentRetVal;\n },\n\n _markFileAsSuccessful: function(id) {\n var templating = this._templating;\n\n if (this._isDeletePossible()) {\n templating.showDeleteButton(id);\n }\n\n qq(templating.getFileContainer(id)).addClass(this._classes.success);\n\n this._maybeUpdateThumbnail(id);\n },\n\n _onUploadPrep: function(id) {\n this._parent.prototype._onUploadPrep.apply(this, arguments);\n this._templating.showSpinner(id);\n },\n\n _onUpload: function(id, name) {\n var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);\n\n this._templating.showSpinner(id);\n\n return parentRetVal;\n },\n\n _onUploadChunk: function(id, chunkData) {\n this._parent.prototype._onUploadChunk.apply(this, arguments);\n\n // Only display the pause button if we have finished uploading at least one chunk\n // & this file can be resumed\n if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {\n this._templating.allowPause(id);\n }\n },\n\n _onCancel: function(id, name) {\n this._parent.prototype._onCancel.apply(this, arguments);\n this._removeFileItem(id);\n\n if (this._getNotFinished() === 0) {\n this._templating.resetTotalProgress();\n }\n },\n\n _onBeforeAutoRetry: function(id) {\n var retryNumForDisplay, maxAuto, retryNote;\n\n this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);\n\n this._showCancelLink(id);\n\n if (this._options.retry.showAutoRetryNote) {\n retryNumForDisplay = this._autoRetries[id];\n maxAuto = this._options.retry.maxAutoAttempts;\n\n retryNote = this._options.retry.autoRetryNote.replace(/\\{retryNum\\}/g, retryNumForDisplay);\n retryNote = retryNote.replace(/\\{maxAuto\\}/g, maxAuto);\n\n this._templating.setStatusText(id, retryNote);\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);\n }\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {\n this._templating.resetProgress(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);\n this._templating.setStatusText(id);\n this._templating.showSpinner(id);\n this._showCancelLink(id);\n return true;\n }\n else {\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);\n this._templating.showRetry(id);\n return false;\n }\n },\n\n _onSubmitDelete: function(id) {\n var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);\n\n this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);\n },\n\n _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {\n if (this._options.deleteFile.forceConfirm) {\n this._showDeleteConfirm.apply(this, arguments);\n }\n else {\n this._sendDeleteRequest.apply(this, arguments);\n }\n },\n\n _onDeleteComplete: function(id, xhr, isError) {\n this._parent.prototype._onDeleteComplete.apply(this, arguments);\n\n this._templating.hideSpinner(id);\n\n if (isError) {\n this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);\n this._templating.showDeleteButton(id);\n }\n else {\n this._removeFileItem(id);\n }\n },\n\n _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {\n this._templating.hideDeleteButton(id);\n this._templating.showSpinner(id);\n this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);\n this._deleteHandler.sendDelete.apply(this, arguments);\n },\n\n _showDeleteConfirm: function(id, uuid, mandatedParams) {\n /*jshint -W004 */\n var fileName = this.getName(id),\n confirmMessage = this._options.deleteFile.confirmMessage.replace(/\\{filename\\}/g, fileName),\n uuid = this.getUuid(id),\n deleteRequestArgs = arguments,\n self = this,\n retVal;\n\n retVal = this._options.showConfirm(confirmMessage);\n\n if (qq.isGenericPromise(retVal)) {\n retVal.then(function() {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n });\n }\n else if (retVal !== false) {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n }\n },\n\n _addToList: function(id, name, canned) {\n var prependData,\n prependIndex = 0,\n dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled,\n record;\n\n if (this._options.display.prependFiles) {\n if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {\n prependIndex = this._filesInBatchAddedToUi - 1;\n }\n\n prependData = {\n index: prependIndex\n };\n }\n\n if (!canned) {\n if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {\n this._templating.disableCancel();\n }\n\n // Cancel all existing (previous) files and clear the list if this file is not part of\n // a scaled file group that has already been accepted, or if this file is not part of\n // a scaled file group at all.\n if (!this._options.multiple) {\n record = this.getUploads({id: id});\n\n this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;\n\n if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {\n this._handler.cancelAll();\n this._clearList();\n this._handledProxyGroup = null;\n }\n }\n }\n\n if (canned) {\n this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);\n }\n else {\n this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);\n }\n\n this._filesInBatchAddedToUi += 1;\n\n if (canned ||\n (this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading)) {\n\n this._displayFileSize(id);\n }\n },\n\n _clearList: function() {\n this._templating.clearFiles();\n this.clearStoredFiles();\n },\n\n _displayFileSize: function(id, loadedSize, totalSize) {\n var size = this.getSize(id),\n sizeForDisplay = this._formatSize(size);\n\n if (size >= 0) {\n if (loadedSize !== undefined && totalSize !== undefined) {\n sizeForDisplay = this._formatProgress(loadedSize, totalSize);\n }\n\n this._templating.updateSize(id, sizeForDisplay);\n }\n },\n\n _formatProgress: function(uploadedSize, totalSize) {\n var message = this._options.text.formatProgress;\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n r(\"{percent}\", Math.round(uploadedSize / totalSize * 100));\n r(\"{total_size}\", this._formatSize(totalSize));\n return message;\n },\n\n _controlFailureTextDisplay: function(id, response) {\n var mode, responseProperty, failureReason;\n\n mode = this._options.failedUploadTextDisplay.mode;\n responseProperty = this._options.failedUploadTextDisplay.responseProperty;\n\n if (mode === \"custom\") {\n failureReason = response[responseProperty];\n if (!failureReason) {\n failureReason = this._options.text.failUpload;\n }\n\n this._templating.setStatusText(id, failureReason);\n\n if (this._options.failedUploadTextDisplay.enableTooltip) {\n this._showTooltip(id, failureReason);\n }\n }\n else if (mode === \"default\") {\n this._templating.setStatusText(id, this._options.text.failUpload);\n }\n else if (mode !== \"none\") {\n this.log(\"failedUploadTextDisplay.mode value of '\" + mode + \"' is not valid\", \"warn\");\n }\n },\n\n _showTooltip: function(id, text) {\n this._templating.getFileContainer(id).title = text;\n },\n\n _showCancelLink: function(id) {\n if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {\n this._templating.showCancel(id);\n }\n },\n\n _itemError: function(code, name, item) {\n var message = this._parent.prototype._itemError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _batchError: function(message) {\n this._parent.prototype._batchError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _setupPastePrompt: function() {\n var self = this;\n\n this._options.callbacks.onPasteReceived = function() {\n var message = self._options.paste.namePromptMessage,\n defaultVal = self._options.paste.defaultName;\n\n return self._options.showPrompt(message, defaultVal);\n };\n },\n\n _fileOrBlobRejected: function(id, name) {\n this._totalFilesInBatch -= 1;\n this._parent.prototype._fileOrBlobRejected.apply(this, arguments);\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n this._totalFilesInBatch = items.length;\n this._filesInBatchAddedToUi = 0;\n this._parent.prototype._prepareItemsForUpload.apply(this, arguments);\n },\n\n _maybeUpdateThumbnail: function(fileId) {\n var thumbnailUrl = this._thumbnailUrls[fileId],\n fileStatus = this.getUploads({id: fileId}).status;\n\n if (fileStatus !== qq.status.DELETED &&\n (thumbnailUrl ||\n this._options.thumbnails.placeholders.waitUntilResponse ||\n !qq.supportedFeatures.imagePreviews)) {\n\n // This will replace the \"waiting\" placeholder with a \"preview not available\" placeholder\n // if called with a null thumbnailUrl.\n this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id = this._parent.prototype._addCannedFile.apply(this, arguments);\n\n this._addToList(id, this.getName(id), true);\n this._templating.hideSpinner(id);\n this._templating.hideCancel(id);\n this._markFileAsSuccessful(id);\n\n return id;\n },\n\n _setSize: function(id, newSize) {\n this._parent.prototype._setSize.apply(this, arguments);\n\n this._templating.updateSize(id, this._formatSize(newSize));\n },\n\n _sessionRequestComplete: function() {\n this._templating.addCacheToDom();\n this._parent.prototype._sessionRequestComplete.apply(this, arguments);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploader mode, which is a default UI w/ drag & drop uploading.\n */\nqq.FineUploader = function(o, namespace) {\n \"use strict\";\n\n var self = this;\n\n // By default this should inherit instance data from FineUploaderBasic, but this can be overridden\n // if the (internal) caller defines a different parent. The parent is also used by\n // the private and public API functions that need to delegate to a parent function.\n this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;\n this._parent.apply(this, arguments);\n\n // Options provided by FineUploader mode\n qq.extend(this._options, {\n element: null,\n\n button: null,\n\n listElement: null,\n\n dragAndDrop: {\n extraDropzones: [],\n reportDirectoryPaths: false\n },\n\n text: {\n formatProgress: \"{percent}% of {total_size}\",\n failUpload: \"Upload failed\",\n waitingForResponse: \"Processing...\",\n paused: \"Paused\"\n },\n\n template: \"qq-template\",\n\n classes: {\n retrying: \"qq-upload-retrying\",\n retryable: \"qq-upload-retryable\",\n success: \"qq-upload-success\",\n fail: \"qq-upload-fail\",\n editable: \"qq-editable\",\n hide: \"qq-hide\",\n dropActive: \"qq-upload-drop-area-active\"\n },\n\n failedUploadTextDisplay: {\n mode: \"default\", //default, custom, or none\n responseProperty: \"error\",\n enableTooltip: true\n },\n\n messages: {\n tooManyFilesError: \"You may only drop one file\",\n unsupportedBrowser: \"Unrecoverable error - this browser does not permit file uploading of any kind.\"\n },\n\n retry: {\n showAutoRetryNote: true,\n autoRetryNote: \"Retrying {retryNum}/{maxAuto}...\"\n },\n\n deleteFile: {\n forceConfirm: false,\n confirmMessage: \"Are you sure you want to delete {filename}?\",\n deletingStatusText: \"Deleting...\",\n deletingFailedText: \"Delete failed\"\n\n },\n\n display: {\n fileSizeOnSubmit: false,\n prependFiles: false\n },\n\n paste: {\n promptForName: false,\n namePromptMessage: \"Please name this image\"\n },\n\n thumbnails: {\n customResizer: null,\n maxCount: 0,\n placeholders: {\n waitUntilResponse: false,\n notAvailablePath: null,\n waitingPath: null\n },\n timeBetweenThumbs: 750\n },\n\n scaling: {\n hideScaled: false\n },\n\n showMessage: function(message) {\n if (self._templating.hasDialog(\"alert\")) {\n return self._templating.showDialog(\"alert\", message);\n }\n else {\n setTimeout(function() {\n window.alert(message);\n }, 0);\n }\n },\n\n showConfirm: function(message) {\n if (self._templating.hasDialog(\"confirm\")) {\n return self._templating.showDialog(\"confirm\", message);\n }\n else {\n return window.confirm(message);\n }\n },\n\n showPrompt: function(message, defaultValue) {\n if (self._templating.hasDialog(\"prompt\")) {\n return self._templating.showDialog(\"prompt\", message, defaultValue);\n }\n else {\n return window.prompt(message, defaultValue);\n }\n }\n }, true);\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._templating = new qq.Templating({\n log: qq.bind(this.log, this),\n templateIdOrEl: this._options.template,\n containerEl: this._options.element,\n fileContainerEl: this._options.listElement,\n button: this._options.button,\n imageGenerator: this._imageGenerator,\n classes: {\n hide: this._options.classes.hide,\n editable: this._options.classes.editable\n },\n limits: {\n maxThumbs: this._options.thumbnails.maxCount,\n timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs\n },\n placeholders: {\n waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,\n thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,\n waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath\n },\n text: this._options.text\n });\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);\n }\n else if (!qq.supportedFeatures.uploading || (this._options.cors.expected && !qq.supportedFeatures.uploadCors)) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowser);\n }\n else {\n this._wrapCallbacks();\n\n this._templating.render();\n\n this._classes = this._options.classes;\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._setupClickAndEditEventHandlers();\n\n if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {\n this._dnd = this._setupDragAndDrop();\n }\n\n if (this._options.paste.targetElement && this._options.paste.promptForName) {\n if (qq.PasteSupport) {\n this._setupPastePrompt();\n }\n else {\n this.log(\"Paste support module not found.\", \"error\");\n }\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n }\n};\n\n// Inherit the base public & private API methods\nqq.extend(qq.FineUploader.prototype, qq.basePublicApi);\nqq.extend(qq.FineUploader.prototype, qq.basePrivateApi);\n\n// Add the FineUploader/default UI public & private UI methods, which may override some base methods.\nqq.extend(qq.FineUploader.prototype, qq.uiPublicApi);\nqq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);\n","/* globals qq */\n/* jshint -W065 */\n/**\n * Module responsible for rendering all Fine Uploader UI templates. This module also asserts at least\n * a limited amount of control over the template elements after they are added to the DOM.\n * Wherever possible, this module asserts total control over template elements present in the DOM.\n *\n * @param spec Specification object used to control various templating behaviors\n * @constructor\n */\nqq.Templating = function(spec) {\n \"use strict\";\n\n var FILE_ID_ATTR = \"qq-file-id\",\n FILE_CLASS_PREFIX = \"qq-file-id-\",\n THUMBNAIL_MAX_SIZE_ATTR = \"qq-max-size\",\n THUMBNAIL_SERVER_SCALE_ATTR = \"qq-server-scale\",\n // This variable is duplicated in the DnD module since it can function as a standalone as well\n HIDE_DROPZONE_ATTR = \"qq-hide-dropzone\",\n DROPZPONE_TEXT_ATTR = \"qq-drop-area-text\",\n IN_PROGRESS_CLASS = \"qq-in-progress\",\n HIDDEN_FOREVER_CLASS = \"qq-hidden-forever\",\n fileBatch = {\n content: document.createDocumentFragment(),\n map: {}\n },\n isCancelDisabled = false,\n generatedThumbnails = 0,\n thumbnailQueueMonitorRunning = false,\n thumbGenerationQueue = [],\n thumbnailMaxSize = -1,\n options = {\n log: null,\n limits: {\n maxThumbs: 0,\n timeBetweenThumbs: 750\n },\n templateIdOrEl: \"qq-template\",\n containerEl: null,\n fileContainerEl: null,\n button: null,\n imageGenerator: null,\n classes: {\n hide: \"qq-hide\",\n editable: \"qq-editable\"\n },\n placeholders: {\n waitUntilUpdate: false,\n thumbnailNotAvailable: null,\n waitingForThumbnail: null\n },\n text: {\n paused: \"Paused\"\n }\n },\n selectorClasses = {\n button: \"qq-upload-button-selector\",\n alertDialog: \"qq-alert-dialog-selector\",\n dialogCancelButton: \"qq-cancel-button-selector\",\n confirmDialog: \"qq-confirm-dialog-selector\",\n dialogMessage: \"qq-dialog-message-selector\",\n dialogOkButton: \"qq-ok-button-selector\",\n promptDialog: \"qq-prompt-dialog-selector\",\n uploader: \"qq-uploader-selector\",\n drop: \"qq-upload-drop-area-selector\",\n list: \"qq-upload-list-selector\",\n progressBarContainer: \"qq-progress-bar-container-selector\",\n progressBar: \"qq-progress-bar-selector\",\n totalProgressBarContainer: \"qq-total-progress-bar-container-selector\",\n totalProgressBar: \"qq-total-progress-bar-selector\",\n file: \"qq-upload-file-selector\",\n spinner: \"qq-upload-spinner-selector\",\n size: \"qq-upload-size-selector\",\n cancel: \"qq-upload-cancel-selector\",\n pause: \"qq-upload-pause-selector\",\n continueButton: \"qq-upload-continue-selector\",\n deleteButton: \"qq-upload-delete-selector\",\n retry: \"qq-upload-retry-selector\",\n statusText: \"qq-upload-status-text-selector\",\n editFilenameInput: \"qq-edit-filename-selector\",\n editNameIcon: \"qq-edit-filename-icon-selector\",\n dropText: \"qq-upload-drop-area-text-selector\",\n dropProcessing: \"qq-drop-processing-selector\",\n dropProcessingSpinner: \"qq-drop-processing-spinner-selector\",\n thumbnail: \"qq-thumbnail-selector\"\n },\n previewGeneration = {},\n cachedThumbnailNotAvailableImg = new qq.Promise(),\n cachedWaitingForThumbnailImg = new qq.Promise(),\n log,\n isEditElementsExist,\n isRetryElementExist,\n templateHtml,\n container,\n fileList,\n showThumbnails,\n serverScale,\n\n // During initialization of the templating module we should cache any\n // placeholder images so we can quickly swap them into the file list on demand.\n // Any placeholder images that cannot be loaded/found are simply ignored.\n cacheThumbnailPlaceholders = function() {\n var notAvailableUrl = options.placeholders.thumbnailNotAvailable,\n waitingUrl = options.placeholders.waitingForThumbnail,\n spec = {\n maxSize: thumbnailMaxSize,\n scale: serverScale\n };\n\n if (showThumbnails) {\n if (notAvailableUrl) {\n options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedThumbnailNotAvailableImg.success(updatedImg);\n },\n function() {\n cachedThumbnailNotAvailableImg.failure();\n log(\"Problem loading 'not available' placeholder image at \" + notAvailableUrl, \"error\");\n }\n );\n }\n else {\n cachedThumbnailNotAvailableImg.failure();\n }\n\n if (waitingUrl) {\n options.imageGenerator.generate(waitingUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedWaitingForThumbnailImg.success(updatedImg);\n },\n function() {\n cachedWaitingForThumbnailImg.failure();\n log(\"Problem loading 'waiting for thumbnail' placeholder image at \" + waitingUrl, \"error\");\n }\n );\n }\n else {\n cachedWaitingForThumbnailImg.failure();\n }\n }\n },\n\n // Displays a \"waiting for thumbnail\" type placeholder image\n // iff we were able to load it during initialization of the templating module.\n displayWaitingImg = function(thumbnail) {\n var waitingImgPlacement = new qq.Promise();\n\n cachedWaitingForThumbnailImg.then(function(img) {\n maybeScalePlaceholderViaCss(img, thumbnail);\n /* jshint eqnull:true */\n if (!thumbnail.src) {\n thumbnail.src = img.src;\n thumbnail.onload = function() {\n thumbnail.onload = null;\n show(thumbnail);\n waitingImgPlacement.success();\n };\n }\n else {\n waitingImgPlacement.success();\n }\n }, function() {\n // In some browsers (such as IE9 and older) an img w/out a src attribute\n // are displayed as \"broken\" images, so we should just hide the img tag\n // if we aren't going to display the \"waiting\" placeholder.\n hide(thumbnail);\n waitingImgPlacement.success();\n });\n\n return waitingImgPlacement;\n },\n\n generateNewPreview = function(id, blob, spec) {\n var thumbnail = getThumbnail(id);\n\n log(\"Generating new thumbnail for \" + id);\n blob.qqThumbnailId = id;\n\n return options.imageGenerator.generate(blob, thumbnail, spec).then(\n function() {\n generatedThumbnails++;\n show(thumbnail);\n previewGeneration[id].success();\n },\n function() {\n previewGeneration[id].failure();\n\n // Display the \"not available\" placeholder img only if we are\n // not expecting a thumbnail at a later point, such as in a server response.\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n }\n });\n },\n\n generateNextQueuedPreview = function() {\n if (thumbGenerationQueue.length) {\n thumbnailQueueMonitorRunning = true;\n\n var queuedThumbRequest = thumbGenerationQueue.shift();\n\n if (queuedThumbRequest.update) {\n processUpdateQueuedPreviewRequest(queuedThumbRequest);\n }\n else {\n processNewQueuedPreviewRequest(queuedThumbRequest);\n }\n }\n else {\n thumbnailQueueMonitorRunning = false;\n }\n },\n\n getCancel = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.cancel);\n },\n\n getContinue = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.continueButton);\n },\n\n getDialog = function(type) {\n return getTemplateEl(container, selectorClasses[type + \"Dialog\"]);\n },\n\n getDelete = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.deleteButton);\n },\n\n getDropProcessing = function() {\n return getTemplateEl(container, selectorClasses.dropProcessing);\n },\n\n getEditIcon = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editNameIcon);\n },\n\n getFile = function(id) {\n return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);\n },\n\n getFilename = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.file);\n },\n\n getPause = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.pause);\n },\n\n getProgress = function(id) {\n /* jshint eqnull:true */\n // Total progress bar\n if (id == null) {\n return getTemplateEl(container, selectorClasses.totalProgressBarContainer) ||\n getTemplateEl(container, selectorClasses.totalProgressBar);\n }\n\n // Per-file progress bar\n return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) ||\n getTemplateEl(getFile(id), selectorClasses.progressBar);\n },\n\n getRetry = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.retry);\n },\n\n getSize = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.size);\n },\n\n getSpinner = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.spinner);\n },\n\n getTemplateEl = function(context, cssClass) {\n return context && qq(context).getFirstByClass(cssClass);\n },\n\n getThumbnail = function(id) {\n return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);\n },\n\n hide = function(el) {\n el && qq(el).addClass(options.classes.hide);\n },\n\n // Ensures a placeholder image does not exceed any max size specified\n // via `style` attribute properties iff was not used to scale\n // the placeholder AND the target doesn't already have these `style` attribute properties set.\n maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {\n var maxWidth = placeholder.style.maxWidth,\n maxHeight = placeholder.style.maxHeight;\n\n if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {\n qq(thumbnail).css({\n maxWidth: maxWidth,\n maxHeight: maxHeight\n });\n }\n },\n\n // Displays a \"thumbnail not available\" type placeholder image\n // iff we were able to load this placeholder during initialization\n // of the templating module or after preview generation has failed.\n maybeSetDisplayNotAvailableImg = function(id, thumbnail) {\n var previewing = previewGeneration[id] || new qq.Promise().failure(),\n notAvailableImgPlacement = new qq.Promise();\n\n cachedThumbnailNotAvailableImg.then(function(img) {\n previewing.then(\n function() {\n notAvailableImgPlacement.success();\n },\n function() {\n maybeScalePlaceholderViaCss(img, thumbnail);\n\n thumbnail.onload = function() {\n thumbnail.onload = null;\n notAvailableImgPlacement.success();\n };\n\n thumbnail.src = img.src;\n show(thumbnail);\n }\n );\n });\n\n return notAvailableImgPlacement;\n },\n\n /**\n * Grabs the HTML from the script tag holding the template markup. This function will also adjust\n * some internally-tracked state variables based on the contents of the template.\n * The template is filtered so that irrelevant elements (such as the drop zone if DnD is not supported)\n * are omitted from the DOM. Useful errors will be thrown if the template cannot be parsed.\n *\n * @returns {{template: *, fileTemplate: *}} HTML for the top-level file items templates\n */\n parseAndGetTemplate = function() {\n var scriptEl,\n scriptHtml,\n fileListNode,\n tempTemplateEl,\n fileListHtml,\n defaultButton,\n dropArea,\n thumbnail,\n dropProcessing,\n dropTextEl,\n uploaderEl;\n\n log(\"Parsing template\");\n\n /*jshint -W116*/\n if (options.templateIdOrEl == null) {\n throw new Error(\"You MUST specify either a template element or ID!\");\n }\n\n // Grab the contents of the script tag holding the template.\n if (qq.isString(options.templateIdOrEl)) {\n scriptEl = document.getElementById(options.templateIdOrEl);\n\n if (scriptEl === null) {\n throw new Error(qq.format(\"Cannot find template script at ID '{}'!\", options.templateIdOrEl));\n }\n\n scriptHtml = scriptEl.innerHTML;\n }\n else {\n if (options.templateIdOrEl.innerHTML === undefined) {\n throw new Error(\"You have specified an invalid value for the template option! \" +\n \"It must be an ID or an Element.\");\n }\n\n scriptHtml = options.templateIdOrEl.innerHTML;\n }\n\n scriptHtml = qq.trimStr(scriptHtml);\n tempTemplateEl = document.createElement(\"div\");\n tempTemplateEl.appendChild(qq.toElement(scriptHtml));\n uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);\n\n // Don't include the default template button in the DOM\n // if an alternate button container has been specified.\n if (options.button) {\n defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);\n if (defaultButton) {\n qq(defaultButton).remove();\n }\n }\n\n // Omit the drop processing element from the DOM if DnD is not supported by the UA,\n // or the drag and drop module is not found.\n // NOTE: We are consciously not removing the drop zone if the UA doesn't support DnD\n // to support layouts where the drop zone is also a container for visible elements,\n // such as the file list.\n if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {\n dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);\n if (dropProcessing) {\n qq(dropProcessing).remove();\n }\n }\n\n dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);\n\n // If DnD is not available then remove\n // it from the DOM as well.\n if (dropArea && !qq.DragAndDrop) {\n log(\"DnD module unavailable.\", \"info\");\n qq(dropArea).remove();\n }\n\n if (!qq.supportedFeatures.fileDrop) {\n // don't display any \"drop files to upload\" background text\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {\n // If there is a drop area defined in the template, and the current UA doesn't support DnD,\n // and the drop area is marked as \"hide before enter\", ensure it is hidden as the DnD module\n // will not do this (since we will not be loading the DnD module)\n qq(dropArea).css({\n display: \"none\"\n });\n }\n }\n else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {\n dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);\n dropTextEl && qq(dropTextEl).remove();\n }\n\n // Ensure the `showThumbnails` flag is only set if the thumbnail element\n // is present in the template AND the current UA is capable of generating client-side previews.\n thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);\n if (!showThumbnails) {\n thumbnail && qq(thumbnail).remove();\n }\n else if (thumbnail) {\n thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));\n // Only enforce max size if the attr value is non-zero\n thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;\n\n serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);\n }\n showThumbnails = showThumbnails && thumbnail;\n\n isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;\n isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;\n\n fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);\n /*jshint -W116*/\n if (fileListNode == null) {\n throw new Error(\"Could not find the file list container in the template!\");\n }\n\n fileListHtml = fileListNode.innerHTML;\n fileListNode.innerHTML = \"\";\n\n // We must call `createElement` in IE8 in order to target and hide any via CSS\n if (tempTemplateEl.getElementsByTagName(\"DIALOG\").length) {\n document.createElement(\"dialog\");\n }\n\n log(\"Template parsing complete\");\n\n return {\n template: qq.trimStr(tempTemplateEl.innerHTML),\n fileTemplate: qq.trimStr(fileListHtml)\n };\n },\n\n prependFile = function(el, index, fileList) {\n var parentEl = fileList,\n beforeEl = parentEl.firstChild;\n\n if (index > 0) {\n beforeEl = qq(parentEl).children()[index].nextSibling;\n\n }\n\n parentEl.insertBefore(el, beforeEl);\n },\n\n processNewQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n optFileOrBlob = queuedThumbRequest.optFileOrBlob,\n relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n maxSize: thumbnailMaxSize,\n orient: true,\n scale: true\n };\n\n if (qq.supportedFeatures.imagePreviews) {\n if (thumbnail) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n displayWaitingImg(thumbnail).done(function() {\n previewGeneration[id] = new qq.Promise();\n\n previewGeneration[id].done(function() {\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n });\n\n /* jshint eqnull: true */\n // If we've already generated an for this file, use the one that exists,\n // don't waste resources generating a new one.\n if (relatedThumbnailId != null) {\n useCachedPreview(id, relatedThumbnailId);\n }\n else {\n generateNewPreview(id, optFileOrBlob, spec);\n }\n });\n }\n }\n // File element in template may have been removed, so move on to next item in queue\n else {\n generateNextQueuedPreview();\n }\n }\n else if (thumbnail) {\n displayWaitingImg(thumbnail);\n generateNextQueuedPreview();\n }\n },\n\n processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n thumbnailUrl = queuedThumbRequest.thumbnailUrl,\n showWaitingImg = queuedThumbRequest.showWaitingImg,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n scale: serverScale,\n maxSize: thumbnailMaxSize\n };\n\n if (thumbnail) {\n if (thumbnailUrl) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n if (showWaitingImg) {\n displayWaitingImg(thumbnail);\n }\n\n return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(\n function() {\n show(thumbnail);\n generatedThumbnails++;\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n },\n\n function() {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n }\n );\n }\n }\n else {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n }\n },\n\n setProgressBarWidth = function(id, percent) {\n var bar = getProgress(id),\n /* jshint eqnull:true */\n progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;\n\n if (bar && !qq(bar).hasClass(progressBarSelector)) {\n bar = qq(bar).getFirstByClass(progressBarSelector);\n }\n\n if (bar) {\n qq(bar).css({width: percent + \"%\"});\n bar.setAttribute(\"aria-valuenow\", percent);\n }\n },\n\n show = function(el) {\n el && qq(el).removeClass(options.classes.hide);\n },\n\n useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {\n var targetThumbnail = getThumbnail(targetThumbnailId),\n cachedThumbnail = getThumbnail(cachedThumbnailId);\n\n log(qq.format(\"ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.\", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));\n\n // Generation of the related thumbnail may still be in progress, so, wait until it is done.\n previewGeneration[cachedThumbnailId].then(function() {\n generatedThumbnails++;\n previewGeneration[targetThumbnailId].success();\n log(qq.format(\"Now using previously generated thumbnail created for ID {} on ID {}.\", cachedThumbnailId, targetThumbnailId));\n targetThumbnail.src = cachedThumbnail.src;\n show(targetThumbnail);\n },\n function() {\n previewGeneration[targetThumbnailId].failure();\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);\n }\n });\n };\n\n qq.extend(options, spec);\n log = options.log;\n\n // No need to worry about conserving CPU or memory on older browsers,\n // since there is no ability to preview, and thumbnail display is primitive and quick.\n if (!qq.supportedFeatures.imagePreviews) {\n options.limits.timeBetweenThumbs = 0;\n options.limits.maxThumbs = 0;\n }\n\n container = options.containerEl;\n showThumbnails = options.imageGenerator !== undefined;\n templateHtml = parseAndGetTemplate();\n\n cacheThumbnailPlaceholders();\n\n qq.extend(this, {\n render: function() {\n log(\"Rendering template in DOM.\");\n\n generatedThumbnails = 0;\n\n container.innerHTML = templateHtml.template;\n hide(getDropProcessing());\n this.hideTotalProgress();\n fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);\n\n log(\"Template rendering complete\");\n },\n\n renderFailure: function(message) {\n var cantRenderEl = qq.toElement(message);\n container.innerHTML = \"\";\n container.appendChild(cantRenderEl);\n },\n\n reset: function() {\n this.render();\n },\n\n clearFiles: function() {\n fileList.innerHTML = \"\";\n },\n\n disableCancel: function() {\n isCancelDisabled = true;\n },\n\n addFile: function(id, name, prependInfo, hideForever, batch) {\n var fileEl = qq.toElement(templateHtml.fileTemplate),\n fileNameEl = getTemplateEl(fileEl, selectorClasses.file),\n uploaderEl = getTemplateEl(container, selectorClasses.uploader),\n fileContainer = batch ? fileBatch.content : fileList,\n thumb;\n\n if (batch) {\n fileBatch.map[id] = fileEl;\n }\n\n qq(fileEl).addClass(FILE_CLASS_PREFIX + id);\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (fileNameEl) {\n qq(fileNameEl).setText(name);\n fileNameEl.setAttribute(\"title\", name);\n }\n\n fileEl.setAttribute(FILE_ID_ATTR, id);\n\n if (prependInfo) {\n prependFile(fileEl, prependInfo.index, fileContainer);\n }\n else {\n fileContainer.appendChild(fileEl);\n }\n\n if (hideForever) {\n fileEl.style.display = \"none\";\n qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);\n }\n else {\n hide(getProgress(id));\n hide(getSize(id));\n hide(getDelete(id));\n hide(getRetry(id));\n hide(getPause(id));\n hide(getContinue(id));\n\n if (isCancelDisabled) {\n this.hideCancel(id);\n }\n\n thumb = getThumbnail(id);\n if (thumb && !thumb.src) {\n cachedWaitingForThumbnailImg.then(function(waitingImg) {\n thumb.src = waitingImg.src;\n if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {\n qq(thumb).css({\n maxHeight: waitingImg.style.maxHeight,\n maxWidth: waitingImg.style.maxWidth\n });\n }\n\n show(thumb);\n });\n }\n }\n },\n\n addFileToCache: function(id, name, prependInfo, hideForever) {\n this.addFile(id, name, prependInfo, hideForever, true);\n },\n\n addCacheToDom: function() {\n fileList.appendChild(fileBatch.content);\n fileBatch.content = document.createDocumentFragment();\n fileBatch.map = {};\n },\n\n removeFile: function(id) {\n qq(getFile(id)).remove();\n },\n\n getFileId: function(el) {\n var currentNode = el;\n\n if (currentNode) {\n /*jshint -W116*/\n while (currentNode.getAttribute(FILE_ID_ATTR) == null) {\n currentNode = currentNode.parentNode;\n }\n\n return parseInt(currentNode.getAttribute(FILE_ID_ATTR));\n }\n },\n\n getFileList: function() {\n return fileList;\n },\n\n markFilenameEditable: function(id) {\n var filename = getFilename(id);\n\n filename && qq(filename).addClass(options.classes.editable);\n },\n\n updateFilename: function(id, name) {\n var filenameEl = getFilename(id);\n\n if (filenameEl) {\n qq(filenameEl).setText(name);\n filenameEl.setAttribute(\"title\", name);\n }\n },\n\n hideFilename: function(id) {\n hide(getFilename(id));\n },\n\n showFilename: function(id) {\n show(getFilename(id));\n },\n\n isFileName: function(el) {\n return qq(el).hasClass(selectorClasses.file);\n },\n\n getButton: function() {\n return options.button || getTemplateEl(container, selectorClasses.button);\n },\n\n hideDropProcessing: function() {\n hide(getDropProcessing());\n },\n\n showDropProcessing: function() {\n show(getDropProcessing());\n },\n\n getDropZone: function() {\n return getTemplateEl(container, selectorClasses.drop);\n },\n\n isEditFilenamePossible: function() {\n return isEditElementsExist;\n },\n\n hideRetry: function(id) {\n hide(getRetry(id));\n },\n\n isRetryPossible: function() {\n return isRetryElementExist;\n },\n\n showRetry: function(id) {\n show(getRetry(id));\n },\n\n getFileContainer: function(id) {\n return getFile(id);\n },\n\n showEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).addClass(options.classes.editable);\n },\n\n isHiddenForever: function(id) {\n return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);\n },\n\n hideEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).removeClass(options.classes.editable);\n },\n\n isEditIcon: function(el) {\n return qq(el).hasClass(selectorClasses.editNameIcon, true);\n },\n\n getEditInput: function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);\n },\n\n isEditInput: function(el) {\n return qq(el).hasClass(selectorClasses.editFilenameInput, true);\n },\n\n updateProgress: function(id, loaded, total) {\n var bar = getProgress(id),\n percent;\n\n if (bar && total > 0) {\n percent = Math.round(loaded / total * 100);\n\n if (percent === 100) {\n hide(bar);\n }\n else {\n show(bar);\n }\n\n setProgressBarWidth(id, percent);\n }\n },\n\n updateTotalProgress: function(loaded, total) {\n this.updateProgress(null, loaded, total);\n },\n\n hideProgress: function(id) {\n var bar = getProgress(id);\n\n bar && hide(bar);\n },\n\n hideTotalProgress: function() {\n this.hideProgress();\n },\n\n resetProgress: function(id) {\n setProgressBarWidth(id, 0);\n this.hideTotalProgress(id);\n },\n\n resetTotalProgress: function() {\n this.resetProgress();\n },\n\n showCancel: function(id) {\n if (!isCancelDisabled) {\n var cancel = getCancel(id);\n\n cancel && qq(cancel).removeClass(options.classes.hide);\n }\n },\n\n hideCancel: function(id) {\n hide(getCancel(id));\n },\n\n isCancel: function(el) {\n return qq(el).hasClass(selectorClasses.cancel, true);\n },\n\n allowPause: function(id) {\n show(getPause(id));\n hide(getContinue(id));\n },\n\n uploadPaused: function(id) {\n this.setStatusText(id, options.text.paused);\n this.allowContinueButton(id);\n hide(getSpinner(id));\n },\n\n hidePause: function(id) {\n hide(getPause(id));\n },\n\n isPause: function(el) {\n return qq(el).hasClass(selectorClasses.pause, true);\n },\n\n isContinueButton: function(el) {\n return qq(el).hasClass(selectorClasses.continueButton, true);\n },\n\n allowContinueButton: function(id) {\n show(getContinue(id));\n hide(getPause(id));\n },\n\n uploadContinued: function(id) {\n this.setStatusText(id, \"\");\n this.allowPause(id);\n show(getSpinner(id));\n },\n\n showDeleteButton: function(id) {\n show(getDelete(id));\n },\n\n hideDeleteButton: function(id) {\n hide(getDelete(id));\n },\n\n isDeleteButton: function(el) {\n return qq(el).hasClass(selectorClasses.deleteButton, true);\n },\n\n isRetry: function(el) {\n return qq(el).hasClass(selectorClasses.retry, true);\n },\n\n updateSize: function(id, text) {\n var size = getSize(id);\n\n if (size) {\n show(size);\n qq(size).setText(text);\n }\n },\n\n setStatusText: function(id, text) {\n var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);\n\n if (textEl) {\n /*jshint -W116*/\n if (text == null) {\n qq(textEl).clearText();\n }\n else {\n qq(textEl).setText(text);\n }\n }\n },\n\n hideSpinner: function(id) {\n qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);\n hide(getSpinner(id));\n },\n\n showSpinner: function(id) {\n qq(getFile(id)).addClass(IN_PROGRESS_CLASS);\n show(getSpinner(id));\n },\n\n generatePreview: function(id, optFileOrBlob, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({id: id, customResizeFunction: customResizeFunction, optFileOrBlob: optFileOrBlob});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({customResizeFunction: customResizeFunction, update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n hasDialog: function(type) {\n return qq.supportedFeatures.dialogElement && !!getDialog(type);\n },\n\n showDialog: function(type, message, defaultValue) {\n var dialog = getDialog(type),\n messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage),\n inputEl = dialog.getElementsByTagName(\"INPUT\")[0],\n cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton),\n okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton),\n promise = new qq.Promise(),\n\n closeHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.removeEventListener(\"click\", okClickHandler);\n promise.failure();\n },\n\n cancelClickHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n dialog.close();\n },\n\n okClickHandler = function() {\n dialog.removeEventListener(\"close\", closeHandler);\n okBtn.removeEventListener(\"click\", okClickHandler);\n dialog.close();\n\n promise.success(inputEl && inputEl.value);\n };\n\n dialog.addEventListener(\"close\", closeHandler);\n cancelBtn.addEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.addEventListener(\"click\", okClickHandler);\n\n if (inputEl) {\n inputEl.value = defaultValue;\n }\n messageEl.textContent = message;\n\n dialog.showModal();\n\n return promise;\n }\n });\n};\n","/*globals qq */\n// Base handler for UI (FineUploader mode) events.\n// Some more specific handlers inherit from this one.\nqq.UiEventHandler = function(s, protectedApi) {\n \"use strict\";\n\n var disposer = new qq.DisposeSupport(),\n spec = {\n eventType: \"click\",\n attachTo: null,\n onHandled: function(target, event) {}\n };\n\n // This makes up the \"public\" API methods that will be accessible\n // to instances constructing a base or child handler\n qq.extend(this, {\n addHandler: function(element) {\n addHandler(element);\n },\n\n dispose: function() {\n disposer.dispose();\n }\n });\n\n function addHandler(element) {\n disposer.attach(element, spec.eventType, function(event) {\n // Only in IE: the `event` is a property of the `window`.\n event = event || window.event;\n\n // On older browsers, we must check the `srcElement` instead of the `target`.\n var target = event.target || event.srcElement;\n\n spec.onHandled(target, event);\n });\n }\n\n // These make up the \"protected\" API methods that children of this base handler will utilize.\n qq.extend(protectedApi, {\n getFileIdFromItem: function(item) {\n return item.qqFileId;\n },\n\n getDisposeSupport: function() {\n return disposer;\n }\n });\n\n qq.extend(spec, s);\n\n if (spec.attachTo) {\n addHandler(spec.attachTo);\n }\n};\n","/* global qq */\nqq.FileButtonsClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n onDeleteFile: function(fileId) {},\n onCancel: function(fileId) {},\n onRetry: function(fileId) {},\n onPause: function(fileId) {},\n onContinue: function(fileId) {},\n onGetName: function(fileId) {}\n },\n buttonHandlers = {\n cancel: function(id) { spec.onCancel(id); },\n retry: function(id) { spec.onRetry(id); },\n deleteButton: function(id) { spec.onDeleteFile(id); },\n pause: function(id) { spec.onPause(id); },\n continueButton: function(id) { spec.onContinue(id); }\n };\n\n function examineEvent(target, event) {\n qq.each(buttonHandlers, function(buttonType, handler) {\n var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1),\n fileId;\n\n if (spec.templating[\"is\" + firstLetterCapButtonType](target)) {\n fileId = spec.templating.getFileId(target);\n qq.preventDefault(event);\n spec.log(qq.format(\"Detected valid file button click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n handler(fileId);\n return false;\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect click events on filename display elements.\nqq.FilenameClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n classes: {\n file: \"qq-upload-file\",\n editNameIcon: \"qq-edit-filename-icon\"\n },\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {}\n };\n\n qq.extend(spec, s);\n\n // This will be called by the parent handler when a `click` event is received on the list element.\n function examineEvent(target, event) {\n if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n // We only allow users to change filenames of files that have been submitted but not yet uploaded.\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n qq.preventDefault(event);\n\n inheritedInternalApi.handleFilenameEdit(fileId, target, true);\n }\n }\n }\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect focusin events on file edit input elements.\nqq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n onGetUploadStatus: function(fileId) {},\n log: function(message, lvl) {}\n };\n\n if (!inheritedInternalApi) {\n inheritedInternalApi = {};\n }\n\n // This will be called by the parent handler when a `focusin` event is received on the list element.\n function handleInputFocus(target, event) {\n if (spec.templating.isEditInput(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename input focus event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n inheritedInternalApi.handleFilenameEdit(fileId, target);\n }\n }\n }\n\n spec.eventType = \"focusin\";\n spec.onHandled = handleInputFocus;\n\n qq.extend(spec, s);\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n/**\n * Child of FilenameInputFocusInHandler. Used to detect focus events on file edit input elements. This child module is only\n * needed for UAs that do not support the focusin event. Currently, only Firefox lacks this event.\n *\n * @param spec Overrides for default specifications\n */\nqq.FilenameInputFocusHandler = function(spec) {\n \"use strict\";\n\n spec.eventType = \"focus\";\n spec.attachTo = null;\n\n qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));\n};\n","/*globals qq */\n// Handles edit-related events on a file item (FineUploader mode). This is meant to be a parent handler.\n// Children will delegate to this handler when specific edit-related actions are detected.\nqq.FilenameEditHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n log: function(message, lvl) {},\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {},\n onSetName: function(fileId, newName) {},\n onEditingStatusChange: function(fileId, isEditing) {}\n };\n\n function getFilenameSansExtension(fileId) {\n var filenameSansExt = spec.onGetName(fileId),\n extIdx = filenameSansExt.lastIndexOf(\".\");\n\n if (extIdx > 0) {\n filenameSansExt = filenameSansExt.substr(0, extIdx);\n }\n\n return filenameSansExt;\n }\n\n function getOriginalExtension(fileId) {\n var origName = spec.onGetName(fileId);\n return qq.getExtension(origName);\n }\n\n // Callback iff the name has been changed\n function handleNameUpdate(newFilenameInputEl, fileId) {\n var newName = newFilenameInputEl.value,\n origExtension;\n\n if (newName !== undefined && qq.trimStr(newName).length > 0) {\n origExtension = getOriginalExtension(fileId);\n\n if (origExtension !== undefined) {\n newName = newName + \".\" + origExtension;\n }\n\n spec.onSetName(fileId, newName);\n }\n\n spec.onEditingStatusChange(fileId, false);\n }\n\n // The name has been updated if the filename edit input loses focus.\n function registerInputBlurHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"blur\", function() {\n handleNameUpdate(inputEl, fileId);\n });\n }\n\n // The name has been updated if the user presses enter.\n function registerInputEnterKeyHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"keyup\", function(event) {\n\n var code = event.keyCode || event.which;\n\n if (code === 13) {\n handleNameUpdate(inputEl, fileId);\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n\n qq.extend(inheritedInternalApi, {\n handleFilenameEdit: function(id, target, focusInput) {\n var newFilenameInputEl = spec.templating.getEditInput(id);\n\n spec.onEditingStatusChange(id, true);\n\n newFilenameInputEl.value = getFilenameSansExtension(id);\n\n if (focusInput) {\n newFilenameInputEl.focus();\n }\n\n registerInputBlurHandler(newFilenameInputEl, id);\n registerInputEnterKeyHandler(newFilenameInputEl, id);\n }\n });\n};\n","/*globals qq */\n/**\n * This defines FineUploader mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader as well as code to handle uploads directly to Azure.\n * This module inherits all logic from UI & core mode and adds some UI-related logic\n * specific to the upload-to-Azure workflow. Some inherited options and API methods have a special meaning\n * in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploader = function(o) {\n var options = {\n failedUploadTextDisplay: {\n mode: \"custom\"\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Inherit instance data from FineUploader, which should in turn inherit from azure.FineUploaderBasic.\n qq.FineUploader.call(this, options, \"azure\");\n };\n\n // Inherit the API methods from FineUploaderBasicS3\n qq.extend(qq.azure.FineUploader.prototype, qq.azure.FineUploaderBasic.prototype);\n\n // Inherit public and private API methods related to UI\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPublicApi);\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploader.prototype, {\n });\n}());\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.min.js b/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.min.js
new file mode 100644
index 000000000000..6f05b61364f7
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.min.js
@@ -0,0 +1,7 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+!function(global,global){!function(e){"use strict";function t(e){var t=s(e||{}),i=n(t);return o(i),a(t,i),d}function n(e){var t=r("uploaderType"),n=r("endpointType");return t?(t=t.charAt(0).toUpperCase()+t.slice(1).toLowerCase(),n?new qq[n]["FineUploader"+t](e):new qq["FineUploader"+t](e)):n?new qq[n].FineUploader(e):new qq.FineUploader(e)}function i(e,t){var n=d.data("fineuploader");return t?(void 0===n&&(n={}),n[e]=t,d.data("fineuploader",n),void 0):void 0===n?null:n[e]}function o(e){return i("uploader",e)}function r(e,t){return i(e,t)}function a(t,n){var i=t.callbacks={};e.each(n._options.callbacks,function(t,n){var o,r;o=/^on(\w+)/.exec(t)[1],o=o.substring(0,1).toLowerCase()+o.substring(1),r=d,i[t]=function(){var t,i,a=Array.prototype.slice.call(arguments),s=[];e.each(a,function(e,t){s.push(c(t))}),t=n.apply(this,a);try{i=r.triggerHandler(o,s)}catch(e){qq.log("Caught error in Fine Uploader jQuery event handler: "+e.message,"error")}return null!=t?t:i}}),n._options.callbacks=i}function s(t,n){var i,o;if(i=void 0===n?"basic"!==t.uploaderType?{element:d[0]}:{}:n,e.each(t,function(t,n){e.inArray(t,p)>=0?r(t,n):n instanceof e?i[t]=n[0]:e.isPlainObject(n)?(i[t]={},s(n,i[t])):e.isArray(n)?(o=[],e.each(n,function(t,n){var i={};n instanceof e?e.merge(o,n):e.isPlainObject(n)?(s(n,i),o.push(i)):o.push(n)}),i[t]=o):i[t]=n}),void 0===n)return i}function l(t){return"string"===e.type(t)&&!t.match(/^_/)&&void 0!==o()[t]}function u(e){var t,n=[],i=Array.prototype.slice.call(arguments,1);return s(i,n),t=o()[e].apply(o(),n),c(t)}function c(t){var n=t;return null==t||"object"!=typeof t||1!==t.nodeType&&9!==t.nodeType||!t.cloneNode||(n=e(t)),n}var d,p=["uploaderType","endpointType"];e.fn.fineUploader=function(n){var i=this,r=arguments,a=[];return this.each(function(s,c){if(d=e(c),o()&&l(n)){if(a.push(u.apply(i,r)),1===i.length)return!1}else"object"!=typeof n&&n?e.error("Method "+n+" does not exist on jQuery.fineUploader"):t.apply(i,r)}),1===a.length?a[0]:a.length>1?a:this}}(jQuery),function(e){"use strict";function t(e){e||(e={}),e.dropZoneElements=[l];var t=r(e);return o(t),i(new qq.DragAndDrop(t)),l}function n(e,t){var n=l.data(u);return t?(void 0===n&&(n={}),n[e]=t,l.data(u,n),void 0):void 0===n?null:n[e]}function i(e){return n("dndInstance",e)}function o(t){var n=t.callbacks={};e.each(new qq.DragAndDrop.callbacks,function(e,t){var i,o=e;i=l,n[e]=function(){var e=Array.prototype.slice.call(arguments),t=i.triggerHandler(o,e);return t}})}function r(t,n){var i,o;if(i=void 0===n?{}:n,e.each(t,function(t,n){n instanceof e?i[t]=n[0]:e.isPlainObject(n)?(i[t]={},r(n,i[t])):e.isArray(n)?(o=[],e.each(n,function(t,n){n instanceof e?e.merge(o,n):o.push(n)}),i[t]=o):i[t]=n}),void 0===n)return i}function a(t){return"string"===e.type(t)&&"dispose"===t&&void 0!==i()[t]}function s(e){var t=[],n=Array.prototype.slice.call(arguments,1);return r(n,t),i()[e].apply(i(),t)}var l,u="fineUploaderDnd";e.fn.fineUploaderDnd=function(n){var o=this,r=arguments,u=[];return this.each(function(c,d){if(l=e(d),i()&&a(n)){if(u.push(s.apply(o,r)),1===o.length)return!1}else"object"!=typeof n&&n?e.error("Method "+n+" does not exist in Fine Uploader's DnD module."):t.apply(o,r)}),1===u.length?u[0]:u.length>1?u:this}}(jQuery),function(e){"use strict";e.fn.fineUploaderAzure=function(t){return"object"==typeof t&&(t.endpointType="azure"),e.fn.fineUploader.apply(this,arguments)}}(jQuery);var qq=function(e){"use strict";return{hide:function(){return e.style.display="none",this},attach:function(t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n),function(){qq(e).detach(t,n)}},detach:function(t,n){return e.removeEventListener?e.removeEventListener(t,n,!1):e.attachEvent&&e.detachEvent("on"+t,n),this},contains:function(t){return!!t&&(e===t||(e.contains?e.contains(t):!!(8&t.compareDocumentPosition(e))))},insertBefore:function(t){return t.parentNode.insertBefore(e,t),this},remove:function(){return e.parentNode.removeChild(e),this},css:function(t){if(null==e.style)throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");return null!=t.opacity&&"string"!=typeof e.style.opacity&&"undefined"!=typeof e.filters&&(t.filter="alpha(opacity="+Math.round(100*t.opacity)+")"),qq.extend(e.style,t),this},hasClass:function(t,n){var i=new RegExp("(^| )"+t+"( |$)");return i.test(e.className)||!(!n||!i.test(e.parentNode.className))},addClass:function(t){return qq(e).hasClass(t)||(e.className+=" "+t),this},removeClass:function(t){var n=new RegExp("(^| )"+t+"( |$)");return e.className=e.className.replace(n," ").replace(/^\s+|\s+$/g,""),this},getByClass:function(t,n){var i,o=[];return n&&e.querySelector?e.querySelector("."+t):e.querySelectorAll?e.querySelectorAll("."+t):(i=e.getElementsByTagName("*"),qq.each(i,function(e,n){qq(n).hasClass(t)&&o.push(n)}),n?o[0]:o)},getFirstByClass:function(t){return qq(e).getByClass(t,!0)},children:function(){for(var t=[],n=e.firstChild;n;)1===n.nodeType&&t.push(n),n=n.nextSibling;return t},setText:function(t){return e.innerText=t,e.textContent=t,this},clearText:function(){return qq(e).setText("")},hasAttribute:function(t){var n;return e.hasAttribute?!!e.hasAttribute(t)&&null==/^false$/i.exec(e.getAttribute(t)):(n=e[t],void 0!==n&&null==/^false$/i.exec(n))}}};!function(){"use strict";qq.canvasToBlob=function(e,t,n){return qq.dataUriToBlob(e.toDataURL(t,n))},qq.dataUriToBlob=function(e){var t,n,i,o,r=function(e,t){var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})};return n=e.split(",")[0].indexOf("base64")>=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),o=e.split(",")[0].split(":")[1].split(";")[0],t=new ArrayBuffer(n.length),i=new Uint8Array(t),qq.each(n,function(e,t){i[e]=t.charCodeAt(0)}),r(t,o)},qq.log=function(e,t){window.console&&(t&&"info"!==t?window.console[t]?window.console[t](e):window.console.log("<"+t+"> "+e):window.console.log(e))},qq.isObject=function(e){return e&&!e.nodeType&&"[object Object]"===Object.prototype.toString.call(e)},qq.isFunction=function(e){return"function"==typeof e},qq.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)||e&&window.ArrayBuffer&&e.buffer&&e.buffer.constructor===ArrayBuffer},qq.isItemList=function(e){return"[object DataTransferItemList]"===Object.prototype.toString.call(e)},qq.isNodeList=function(e){return"[object NodeList]"===Object.prototype.toString.call(e)||e.item&&e.namedItem},qq.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},qq.trimStr=function(e){return String.prototype.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},qq.format=function(e){var t=Array.prototype.slice.call(arguments,1),n=e,i=n.indexOf("{}");return qq.each(t,function(e,t){var o=n.substring(0,i),r=n.substring(i+2);if(n=o+t+r,i=n.indexOf("{}",i+t.length),i<0)return!1}),n},qq.isFile=function(e){return window.File&&"[object File]"===Object.prototype.toString.call(e)},qq.isFileList=function(e){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(e)},qq.isFileOrInput=function(e){return qq.isFile(e)||qq.isInput(e)},qq.isInput=function(e,t){var n=function(e){var n=e.toLowerCase();return t?"file"!==n:"file"===n};return!!(window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(e)&&e.type&&n(e.type))||!!(e.tagName&&"input"===e.tagName.toLowerCase()&&e.type&&n(e.type))},qq.isBlob=function(e){if(window.Blob&&"[object Blob]"===Object.prototype.toString.call(e))return!0},qq.isXhrUploadSupported=function(){var e=document.createElement("input");return e.type="file",void 0!==e.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&"undefined"!=typeof qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(e){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(e){return e.items&&e.items.length>0&&e.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(e,t,n){var i=e.slice||e.mozSlice||e.webkitSlice;return i.call(e,t,n)},qq.arrayBufferToHex=function(e){var t="",n=new Uint8Array(e);return qq.each(n,function(e,n){var i=n.toString(16);i.length<2&&(i="0"+i),t+=i}),t},qq.readBlobToHex=function(e,t,n){var i=qq.sliceBlob(e,t,t+n),o=new FileReader,r=new qq.Promise;return o.onload=function(){r.success(qq.arrayBufferToHex(o.result))},o.onerror=r.failure,o.readAsArrayBuffer(i),r},qq.extend=function(e,t,n){return qq.each(t,function(t,i){n&&qq.isObject(i)?(void 0===e[t]&&(e[t]={}),qq.extend(e[t],i,!0)):e[t]=i}),e},qq.override=function(e,t){var n={},i=t(n);return qq.each(i,function(t,i){void 0!==e[t]&&(n[t]=e[t]),e[t]=i}),e},qq.indexOf=function(e,t,n){if(e.indexOf)return e.indexOf(t,n);n=n||0;var i=e.length;for(n<0&&(n+=i);n=0},qq.safari=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Apple")!==-1},qq.chrome=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Google")!==-1},qq.opera=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Opera")!==-1},qq.firefox=function(){return!qq.edge()&&!qq.ie11()&&navigator.userAgent.indexOf("Mozilla")!==-1&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return navigator.userAgent.toLowerCase().indexOf("android")!==-1},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 6_")!==-1},qq.ios7=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 7_")!==-1},qq.ios8=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_")!==-1},qq.ios800=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_0 ")!==-1},qq.ios=function(){return navigator.userAgent.indexOf("iPad")!==-1||navigator.userAgent.indexOf("iPod")!==-1||navigator.userAgent.indexOf("iPhone")!==-1},qq.iosChrome=function(){return qq.ios()&&navigator.userAgent.indexOf("CriOS")!==-1},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&navigator.userAgent.indexOf("Safari")!==-1},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},qq.toElement=function(){var e=document.createElement("div");return function(t){e.innerHTML=t;var n=e.firstChild;return e.removeChild(n),n}}(),qq.each=function(e,t){var n,i;if(e)if(window.Storage&&e.constructor===window.Storage)for(n=0;n0)return e.substr(t,e.length-t)},qq.getFilename=function(e){return qq.isInput(e)?e.value.replace(/.*(\/|\\)/,""):qq.isFile(e)&&null!==e.fileName&&void 0!==e.fileName?e.fileName:e.name},qq.DisposeSupport=function(){var e=[];return{dispose:function(){var t;do t=e.shift(),t&&t();while(t)},attach:function(){var e=arguments;this.addDisposer(qq(e[0]).attach.apply(this,Array.prototype.slice.call(arguments,1)))},addDisposer:function(t){e.push(t)}}}}(),function(){"use strict";"function"==typeof define&&define.amd?define(function(){return qq}):"undefined"!=typeof module&&module.exports?module.exports=qq:global.qq=qq}(),function(){"use strict";qq.Error=function(e){this.message="[Fine Uploader "+qq.version+"] "+e},qq.Error.prototype=new Error}(),qq.version="5.13.0",qq.supportedFeatures=function(){"use strict";function e(){var e,t=!0;try{e=document.createElement("input"),e.type="file",qq(e).hide(),e.disabled&&(t=!1)}catch(e){t=!1}return t}function t(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/)}function n(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/)}function i(){if(window.XMLHttpRequest){var e=qq.createXhrInstance();return void 0!==e.withCredentials}return!1}function o(){return void 0!==window.XDomainRequest}function r(){return!!i()||o()}function a(){return void 0!==document.createElement("input").webkitdirectory}function s(){try{return!!window.localStorage&&qq.isFunction(window.localStorage.setItem)}catch(e){return!1}}function l(){var e=document.createElement("span");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&!qq.android()&&!qq.ios()}var u,c,d,p,q,h,f,m,g,_,b,v,y,S,w;return u=e(),p=u&&qq.isXhrUploadSupported(),c=p&&!qq.androidStock(),d=p&&l(),q=d&&t(),h=p&&qq.isFileChunkingSupported(),f=p&&h&&s(),m=p&&n(),g=u&&(void 0!==window.postMessage||p),b=i(),_=o(),v=r(),y=a(),S=p&&void 0!==window.FileReader,w=function(){return!!p&&(!qq.androidStock()&&!qq.iosChrome())}(),{ajaxUploading:p,blobUploading:c,canDetermineSize:p,chunking:h,deleteFileCors:v,deleteFileCorsXdr:_,deleteFileCorsXhr:b,dialogElement:!!window.HTMLDialogElement,fileDrop:d,folderDrop:q,folderSelection:y,imagePreviews:S,imageValidation:S,itemSizeValidation:p,pause:h,progressBar:w,resume:f,scaling:S&&c,tiffPreviews:qq.safari(),unlimitedScaledImageSize:!qq.ios(),uploading:u,uploadCors:g,uploadCustomHeaders:p,uploadNonMultipart:p,uploadViaPaste:m}}(),qq.isGenericPromise=function(e){"use strict";return!!(e&&e.then&&qq.isFunction(e.then))},qq.Promise=function(){"use strict";var e,t,n=[],i=[],o=[],r=0;qq.extend(this,{then:function(o,a){return 0===r?(o&&n.push(o),a&&i.push(a)):r===-1?a&&a.apply(null,t):o&&o.apply(null,e),this},done:function(n){return 0===r?o.push(n):n.apply(null,void 0===t?e:t),this},success:function(){return r=1,e=arguments,n.length&&qq.each(n,function(t,n){n.apply(null,e)}),o.length&&qq.each(o,function(t,n){n.apply(null,e)}),this},failure:function(){return r=-1,t=arguments,i.length&&qq.each(i,function(e,n){n.apply(null,t)}),o.length&&qq.each(o,function(e,n){n.apply(null,t)}),this}})},qq.BlobProxy=function(e,t){"use strict";qq.extend(this,{referenceBlob:e,create:function(){return t(e)}})},qq.UploadButton=function(e){"use strict";function t(){var e=document.createElement("input");return e.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME,i),e.setAttribute("title",a.title),o.setMultiple(a.multiple,e),a.folders&&qq.supportedFeatures.folderSelection&&e.setAttribute("webkitdirectory",""),a.acceptFiles&&e.setAttribute("accept",a.acceptFiles),e.setAttribute("type","file"),e.setAttribute("name",a.name),qq(e).css({position:"absolute",right:0,top:0,fontFamily:"Arial",fontSize:qq.ie()&&!qq.ie8()?"3500px":"118px",margin:0,padding:0,cursor:"pointer",opacity:0}),!qq.ie7()&&qq(e).css({height:"100%"}),a.element.appendChild(e),r.attach(e,"change",function(){a.onChange(e)}),r.attach(e,"mouseover",function(){qq(a.element).addClass(a.hoverClass)}),r.attach(e,"mouseout",function(){qq(a.element).removeClass(a.hoverClass)}),r.attach(e,"focus",function(){qq(a.element).addClass(a.focusClass)}),r.attach(e,"blur",function(){qq(a.element).removeClass(a.focusClass)}),e}var n,i,o=this,r=new qq.DisposeSupport,a={acceptFiles:null,element:null,focusClass:"qq-upload-button-focus",folders:!1,hoverClass:"qq-upload-button-hover",ios8BrowserCrashWorkaround:!1,multiple:!1,name:"qqfile",onChange:function(e){},title:null};qq.extend(a,e),i=qq.getUniqueId(),qq(a.element).css({position:"relative",overflow:"hidden",direction:"ltr"}),qq.extend(this,{getInput:function(){return n},getButtonId:function(){return i},setMultiple:function(e,t){var n=t||this.getInput();a.ios8BrowserCrashWorkaround&&qq.ios8()&&(qq.iosChrome()||qq.iosSafariWebView())?n.setAttribute("multiple",""):e?n.setAttribute("multiple",""):n.removeAttribute("multiple")},setAcceptFiles:function(e){e!==a.acceptFiles&&n.setAttribute("accept",e)},reset:function(){n.parentNode&&qq(n).remove(),qq(a.element).removeClass(a.focusClass),n=null,n=t()}}),n=t()},qq.UploadButton.BUTTON_ID_ATTR_NAME="qq-button-id",qq.UploadData=function(e){"use strict";function t(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[n])}),t}return o[e]}function n(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[r[n]])}),t}return o[r[e]]}function i(e){var t=[],n=[].concat(e);return qq.each(n,function(e,n){var i=a[n];void 0!==i&&qq.each(i,function(e,n){t.push(o[n])})}),t}var o=[],r={},a={},s={},l={};qq.extend(this,{addFile:function(t){var n=t.status||qq.status.SUBMITTING,i=o.push({name:t.name,originalName:t.name,uuid:t.uuid,size:null==t.size?-1:t.size,status:n})-1;return t.batchId&&(o[i].batchId=t.batchId,void 0===l[t.batchId]&&(l[t.batchId]=[]),l[t.batchId].push(i)),t.proxyGroupId&&(o[i].proxyGroupId=t.proxyGroupId,void 0===s[t.proxyGroupId]&&(s[t.proxyGroupId]=[]),s[t.proxyGroupId].push(i)),o[i].id=i,r[t.uuid]=i,void 0===a[n]&&(a[n]=[]),a[n].push(i),e.onStatusChange(i,null,n),i},retrieve:function(e){return qq.isObject(e)&&o.length?void 0!==e.id?t(e.id):void 0!==e.uuid?n(e.uuid):e.status?i(e.status):void 0:qq.extend([],o,!0)},reset:function(){o=[],r={},a={},l={}},setStatus:function(t,n){var i=o[t].status,r=qq.indexOf(a[i],t);a[i].splice(r,1),o[t].status=n,void 0===a[n]&&(a[n]=[]),a[n].push(t),e.onStatusChange(t,i,n)},uuidChanged:function(e,t){var n=o[e].uuid;o[e].uuid=t,r[t]=e,delete r[n]},updateName:function(e,t){o[e].name=t},updateSize:function(e,t){o[e].size=t},setParentId:function(e,t){o[e].parentId=t},getIdsInProxyGroup:function(e){var t=o[e].proxyGroupId;return t?s[t]:[]},getIdsInBatch:function(e){var t=o[e].batchId;return l[t]}})},qq.status={SUBMITTING:"submitting",SUBMITTED:"submitted",REJECTED:"rejected",QUEUED:"queued",CANCELED:"canceled",PAUSED:"paused",UPLOADING:"uploading",UPLOAD_RETRYING:"retrying upload",UPLOAD_SUCCESSFUL:"upload successful",UPLOAD_FAILED:"upload failed",DELETE_FAILED:"delete failed",DELETING:"deleting",DELETED:"deleted"},function(){"use strict";qq.basePublicApi={addBlobs:function(e,t,n){this.addFiles(e,t,n)},addInitialFiles:function(e){var t=this;qq.each(e,function(e,n){t._addCannedFile(n)})},addFiles:function(e,t,n){this._maybeHandleIos8SafariWorkaround();var i=0===this._storedIds.length?qq.getUniqueId():this._currentBatchId,o=qq.bind(function(e){this._handleNewFile({blob:e,name:this._options.blobs.defaultName},i,d)},this),r=qq.bind(function(e){this._handleNewFile(e,i,d)},this),a=qq.bind(function(e){var t=qq.canvasToBlob(e);this._handleNewFile({blob:t,name:this._options.blobs.defaultName+".png"},i,d)},this),s=qq.bind(function(e){var t=e.quality&&e.quality/100,n=qq.canvasToBlob(e.canvas,e.type,t);this._handleNewFile({blob:n,name:e.name},i,d)},this),l=qq.bind(function(e){if(qq.isInput(e)&&qq.supportedFeatures.ajaxUploading){var t=Array.prototype.slice.call(e.files),n=this;qq.each(t,function(e,t){n._handleNewFile(t,i,d)})}else this._handleNewFile(e,i,d)},this),u=function(){qq.isFileList(e)&&(e=Array.prototype.slice.call(e)),e=[].concat(e)},c=this,d=[];this._currentBatchId=i,e&&(u(),qq.each(e,function(e,t){qq.isFileOrInput(t)?l(t):qq.isBlob(t)?o(t):qq.isObject(t)?t.blob&&t.name?r(t):t.canvas&&t.name&&s(t):t.tagName&&"canvas"===t.tagName.toLowerCase()?a(t):c.log(t+" is not a valid file container! Ignoring!","warn")}),this.log("Received "+d.length+" files."),this._prepareItemsForUpload(d,t,n))},cancel:function(e){this._handler.cancel(e)},cancelAll:function(){var e=[],t=this;qq.extend(e,this._storedIds),qq.each(e,function(e,n){t.cancel(n)}),this._handler.cancelAll()},clearStoredFiles:function(){this._storedIds=[]},continueUpload:function(e){var t=this._uploadData.retrieve({id:e});return!(!qq.supportedFeatures.pause||!this._options.chunking.enabled)&&(t.status===qq.status.PAUSED?(this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.",e,this.getName(e))),this._uploadFile(e),!0):(this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.",e,this.getName(e)),"error"),!1))},deleteFile:function(e){return this._onSubmitDelete(e)},doesExist:function(e){return this._handler.isValid(e)},drawThumbnail:function(e,t,n,i,o){var r,a,s=new qq.Promise;return this._imageGenerator?(r=this._thumbnailUrls[e],a={customResizeFunction:o,maxSize:n>0?n:null,scale:n>0},!i&&qq.supportedFeatures.imagePreviews&&(r=this.getFile(e)),null==r?s.failure({container:t,error:"File or URL not found."}):this._imageGenerator.generate(r,t,a).then(function(e){s.success(e)},function(e,t){s.failure({container:e,error:t||"Problem generating thumbnail"})})):s.failure({container:t,error:"Missing image generator module"}),s},getButton:function(e){return this._getButton(this._buttonIdsForFileIds[e])},getEndpoint:function(e){return this._endpointStore.get(e)},getFile:function(e){return this._handler.getFile(e)||null},getInProgress:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED]}).length},getName:function(e){return this._uploadData.retrieve({id:e}).name},getParentId:function(e){var t=this.getUploads({id:e}),n=null;return t&&void 0!==t.parentId&&(n=t.parentId),n},getResumableFilesData:function(){return this._handler.getResumableFilesData()},getSize:function(e){return this._uploadData.retrieve({id:e}).size},getNetUploads:function(){return this._netUploaded},getRemainingAllowedItems:function(){var e=this._currentItemLimit;return e>0?e-this._netUploadedOrQueued:null},getUploads:function(e){return this._uploadData.retrieve(e)},getUuid:function(e){return this._uploadData.retrieve({id:e}).uuid},log:function(e,t){!this._options.debug||t&&"info"!==t?t&&"info"!==t&&qq.log("[Fine Uploader "+qq.version+"] "+e,t):qq.log("[Fine Uploader "+qq.version+"] "+e)},pauseUpload:function(e){var t=this._uploadData.retrieve({id:e});if(!qq.supportedFeatures.pause||!this._options.chunking.enabled)return!1;if(qq.indexOf([qq.status.UPLOADING,qq.status.UPLOAD_RETRYING],t.status)>=0){if(this._handler.pause(e))return this._uploadData.setStatus(e,qq.status.PAUSED),!0;this.log(qq.format("Unable to pause file ID {} ({}).",e,this.getName(e)),"error")}else this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.",e,this.getName(e)),"error");return!1},reset:function(){this.log("Resetting uploader..."),this._handler.reset(),this._storedIds=[],this._autoRetries=[],this._retryTimeouts=[],this._preventRetries=[],this._thumbnailUrls=[],qq.each(this._buttons,function(e,t){t.reset()}),this._paramsStore.reset(),this._endpointStore.reset(),this._netUploadedOrQueued=0,this._netUploaded=0,this._uploadData.reset(),this._buttonIdsForFileIds=[],this._pasteHandler&&this._pasteHandler.reset(),this._options.session.refreshOnReset&&this._refreshSessionData(),this._succeededSinceLastAllComplete=[],this._failedSinceLastAllComplete=[],this._totalProgress&&this._totalProgress.reset()},retry:function(e){return this._manualRetry(e)},scaleImage:function(e,t){var n=this;return qq.Scaler.prototype.scaleImage(e,t,{log:qq.bind(n.log,n),getFile:qq.bind(n.getFile,n),uploadData:n._uploadData})},setCustomHeaders:function(e,t){this._customHeadersStore.set(e,t)},setDeleteFileCustomHeaders:function(e,t){this._deleteFileCustomHeadersStore.set(e,t)},setDeleteFileEndpoint:function(e,t){this._deleteFileEndpointStore.set(e,t)},setDeleteFileParams:function(e,t){this._deleteFileParamsStore.set(e,t)},setEndpoint:function(e,t){this._endpointStore.set(e,t)},setForm:function(e){this._updateFormSupportAndParams(e)},setItemLimit:function(e){this._currentItemLimit=e},setName:function(e,t){this._uploadData.updateName(e,t)},setParams:function(e,t){this._paramsStore.set(e,t)},setUuid:function(e,t){return this._uploadData.uuidChanged(e,t)},uploadStoredFiles:function(){0===this._storedIds.length?this._itemError("noFilesError"):this._uploadStoredFiles()}},qq.basePrivateApi={_addCannedFile:function(e){var t=this._uploadData.addFile({uuid:e.uuid,name:e.name,size:e.size,status:qq.status.UPLOAD_SUCCESSFUL});return e.deleteFileEndpoint&&this.setDeleteFileEndpoint(e.deleteFileEndpoint,t),e.deleteFileParams&&this.setDeleteFileParams(e.deleteFileParams,t),e.thumbnailUrl&&(this._thumbnailUrls[t]=e.thumbnailUrl),this._netUploaded++,this._netUploadedOrQueued++,t},_annotateWithButtonId:function(e,t){qq.isFile(e)&&(e.qqButtonId=this._getButtonId(t))},_batchError:function(e){this._options.callbacks.onError(null,null,e,void 0)},_createDeleteHandler:function(){var e=this;return new qq.DeleteFileAjaxRequester({method:this._options.deleteFile.method.toUpperCase(),maxConnections:this._options.maxConnections,uuidParamName:this._options.request.uuidName,customHeaders:this._deleteFileCustomHeadersStore,paramsStore:this._deleteFileParamsStore,endpointStore:this._deleteFileEndpointStore,cors:this._options.cors,log:qq.bind(e.log,e),onDelete:function(t){e._onDelete(t),e._options.callbacks.onDelete(t)},onDeleteComplete:function(t,n,i){e._onDeleteComplete(t,n,i),e._options.callbacks.onDeleteComplete(t,n,i)}})},_createPasteHandler:function(){var e=this;return new qq.PasteSupport({targetElement:this._options.paste.targetElement,callbacks:{log:qq.bind(e.log,e),pasteReceived:function(t){e._handleCheckedCallback({name:"onPasteReceived",callback:qq.bind(e._options.callbacks.onPasteReceived,e,t),onSuccess:qq.bind(e._handlePasteSuccess,e,t),identifier:"pasted image"})}}})},_createStore:function(e,t){var n={},i=e,o={},r=t,a=function(e){return qq.isObject(e)?qq.extend({},e):e},s=function(){return qq.isFunction(r)?r():r},l=function(e,t){r&&qq.isObject(t)&&qq.extend(t,s()),o[e]&&qq.extend(t,o[e])};return{set:function(e,t){null==t?(n={},i=a(e)):n[t]=a(e)},get:function(e){var t;return t=null!=e&&n[e]?n[e]:a(i),l(e,t),a(t)},addReadOnly:function(e,t){qq.isObject(n)&&(null===e?qq.isFunction(t)?r=t:(r=r||{},qq.extend(r,t)):(o[e]=o[e]||{},qq.extend(o[e],t)))},remove:function(e){return delete n[e]},reset:function(){n={},o={},i=e}}},_createUploadDataTracker:function(){var e=this;return new qq.UploadData({getName:function(t){return e.getName(t)},getUuid:function(t){return e.getUuid(t)},getSize:function(t){return e.getSize(t)},onStatusChange:function(t,n,i){e._onUploadStatusChange(t,n,i),e._options.callbacks.onStatusChange(t,n,i),e._maybeAllComplete(t,i),e._totalProgress&&setTimeout(function(){e._totalProgress.onStatusChange(t,n,i)},0)}})},_createUploadButton:function(e){function t(){return!!qq.supportedFeatures.ajaxUploading&&(!(i._options.workarounds.iosEmptyVideos&&qq.ios()&&!qq.ios6()&&i._isAllowedExtension(r,".mov"))&&(void 0===e.multiple?i._options.multiple:e.multiple))}var n,i=this,o=e.accept||this._options.validation.acceptFiles,r=e.allowedExtensions||this._options.validation.allowedExtensions;return n=new qq.UploadButton({acceptFiles:o,element:e.element,focusClass:this._options.classes.buttonFocus,folders:e.folders,hoverClass:this._options.classes.buttonHover,ios8BrowserCrashWorkaround:this._options.workarounds.ios8BrowserCrash,multiple:t(),name:this._options.request.inputName,onChange:function(e){i._onInputChange(e)},title:null==e.title?this._options.text.fileInputTitle:e.title}),this._disposeSupport.addDisposer(function(){n.dispose()}),i._buttons.push(n),n},_createUploadHandler:function(e,t){var n=this,i={},o={debug:this._options.debug,maxConnections:this._options.maxConnections,cors:this._options.cors,paramsStore:this._paramsStore,endpointStore:this._endpointStore,chunking:this._options.chunking,resume:this._options.resume,blobs:this._options.blobs,log:qq.bind(n.log,n),preventRetryParam:this._options.retry.preventRetryResponseProperty,onProgress:function(e,t,o,r){o<0||r<0||(i[e]?i[e].loaded===o&&i[e].total===r||(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)):(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)),i[e]={loaded:o,total:r})},onComplete:function(e,t,o,r){delete i[e];var a,s=n.getUploads({id:e}).status;s!==qq.status.UPLOAD_SUCCESSFUL&&s!==qq.status.UPLOAD_FAILED&&(a=n._onComplete(e,t,o,r),a instanceof qq.Promise?a.done(function(){n._options.callbacks.onComplete(e,t,o,r)}):n._options.callbacks.onComplete(e,t,o,r))},onCancel:function(e,t,i){var o=new qq.Promise;return n._handleCheckedCallback({name:"onCancel",callback:qq.bind(n._options.callbacks.onCancel,n,e,t),onFailure:o.failure,onSuccess:function(){i.then(function(){n._onCancel(e,t)}),o.success()},identifier:e}),o},onUploadPrep:qq.bind(this._onUploadPrep,this),onUpload:function(e,t){n._onUpload(e,t),n._options.callbacks.onUpload(e,t)},onUploadChunk:function(e,t,i){n._onUploadChunk(e,i),n._options.callbacks.onUploadChunk(e,t,i)},onUploadChunkSuccess:function(e,t,i,o){n._options.callbacks.onUploadChunkSuccess.apply(n,arguments)},onResume:function(e,t,i){return n._options.callbacks.onResume(e,t,i)},onAutoRetry:function(e,t,i,o){return n._onAutoRetry.apply(n,arguments)},onUuidChanged:function(e,t){n.log("Server requested UUID change from '"+n.getUuid(e)+"' to '"+t+"'"),n.setUuid(e,t)},getName:qq.bind(n.getName,n),getUuid:qq.bind(n.getUuid,n),getSize:qq.bind(n.getSize,n),setSize:qq.bind(n._setSize,n),getDataByUuid:function(e){return n.getUploads({uuid:e})},isQueued:function(e){var t=n.getUploads({id:e}).status;return t===qq.status.QUEUED||t===qq.status.SUBMITTED||t===qq.status.UPLOAD_RETRYING||t===qq.status.PAUSED},getIdsInProxyGroup:n._uploadData.getIdsInProxyGroup,getIdsInBatch:n._uploadData.getIdsInBatch};return qq.each(this._options.request,function(e,t){o[e]=t}),o.customHeaders=this._customHeadersStore,e&&qq.each(e,function(e,t){o[e]=t}),new qq.UploadHandlerController(o,t)},_fileOrBlobRejected:function(e){this._netUploadedOrQueued--,
+this._uploadData.setStatus(e,qq.status.REJECTED)},_formatSize:function(e){if(0===e)return e+this._options.text.sizeSymbols[0];var t=-1;do e/=1e3,t++;while(e>999);return Math.max(e,.1).toFixed(1)+this._options.text.sizeSymbols[t]},_generateExtraButtonSpecs:function(){var e=this;this._extraButtonSpecs={},qq.each(this._options.extraButtons,function(t,n){var i=n.multiple,o=qq.extend({},e._options.validation,!0),r=qq.extend({},n);void 0===i&&(i=e._options.multiple),r.validation&&qq.extend(o,n.validation,!0),qq.extend(r,{multiple:i,validation:o},!0),e._initExtraButton(r)})},_getButton:function(e){var t=this._extraButtonSpecs[e];return t?t.element:e===this._defaultButtonId?this._options.button:void 0},_getButtonId:function(e){var t,n,i=e;if(i instanceof qq.BlobProxy&&(i=i.referenceBlob),i&&!qq.isBlob(i)){if(qq.isFile(i))return i.qqButtonId;if("input"===i.tagName.toLowerCase()&&"file"===i.type.toLowerCase())return i.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);if(t=i.getElementsByTagName("input"),qq.each(t,function(e,t){if("file"===t.getAttribute("type"))return n=t,!1}),n)return n.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME)}},_getNotFinished:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED,qq.status.SUBMITTING,qq.status.SUBMITTED,qq.status.PAUSED]}).length},_getValidationBase:function(e){var t=this._extraButtonSpecs[e];return t?t.validation:this._options.validation},_getValidationDescriptor:function(e){return e.file instanceof qq.BlobProxy?{name:qq.getFilename(e.file.referenceBlob),size:e.file.referenceBlob.size}:{name:this.getUploads({id:e.id}).name,size:this.getUploads({id:e.id}).size}},_getValidationDescriptors:function(e){var t=this,n=[];return qq.each(e,function(e,i){n.push(t._getValidationDescriptor(i))}),n},_handleCameraAccess:function(){if(this._options.camera.ios&&qq.ios()){var e="image/*;capture=camera",t=this._options.camera.button,n=t?this._getButtonId(t):this._defaultButtonId,i=this._options;n&&n!==this._defaultButtonId&&(i=this._extraButtonSpecs[n]),i.multiple=!1,null===i.validation.acceptFiles?i.validation.acceptFiles=e:i.validation.acceptFiles+=","+e,qq.each(this._buttons,function(e,t){if(t.getButtonId()===n)return t.setMultiple(i.multiple),t.setAcceptFiles(i.acceptFiles),!1})}},_handleCheckedCallback:function(e){var t=this,n=e.callback();return qq.isGenericPromise(n)?(this.log(e.name+" - waiting for "+e.name+" promise to be fulfilled for "+e.identifier),n.then(function(n){t.log(e.name+" promise success for "+e.identifier),e.onSuccess(n)},function(){e.onFailure?(t.log(e.name+" promise failure for "+e.identifier),e.onFailure()):t.log(e.name+" promise failure for "+e.identifier)})):(n!==!1?e.onSuccess(n):e.onFailure?(this.log(e.name+" - return value was 'false' for "+e.identifier+". Invoking failure callback."),e.onFailure()):this.log(e.name+" - return value was 'false' for "+e.identifier+". Will not proceed."),n)},_handleNewFile:function(e,t,n){var i=this,o=qq.getUniqueId(),r=-1,a=qq.getFilename(e),s=e.blob||e,l=this._customNewFileHandler?this._customNewFileHandler:qq.bind(i._handleNewFileGeneric,i);!qq.isInput(s)&&s.size>=0&&(r=s.size),l(s,a,o,r,n,t,this._options.request.uuidName,{uploadData:i._uploadData,paramsStore:i._paramsStore,addFileToHandler:function(e,t){i._handler.add(e,t),i._netUploadedOrQueued++,i._trackButton(e)}})},_handleNewFileGeneric:function(e,t,n,i,o,r){var a=this._uploadData.addFile({uuid:n,name:t,size:i,batchId:r});this._handler.add(a,e),this._trackButton(a),this._netUploadedOrQueued++,o.push({id:a,file:e})},_handlePasteSuccess:function(e,t){var n=e.type.split("/")[1],i=t;null==i&&(i=this._options.paste.defaultName),i+="."+n,this.addFiles({name:i,blob:e})},_initExtraButton:function(e){var t=this._createUploadButton({accept:e.validation.acceptFiles,allowedExtensions:e.validation.allowedExtensions,element:e.element,folders:e.folders,multiple:e.multiple,title:e.fileInputTitle});this._extraButtonSpecs[t.getButtonId()]=e},_initFormSupportAndParams:function(){this._formSupport=qq.FormSupport&&new qq.FormSupport(this._options.form,qq.bind(this.uploadStoredFiles,this),qq.bind(this.log,this)),this._formSupport&&this._formSupport.attachedToForm?(this._paramsStore=this._createStore(this._options.request.params,this._formSupport.getFormInputsAsObject),this._options.autoUpload=this._formSupport.newAutoUpload,this._formSupport.newEndpoint&&(this._options.request.endpoint=this._formSupport.newEndpoint)):this._paramsStore=this._createStore(this._options.request.params)},_isDeletePossible:function(){return!(!qq.DeleteFileAjaxRequester||!this._options.deleteFile.enabled)&&(!this._options.cors.expected||(!!qq.supportedFeatures.deleteFileCorsXhr||!(!qq.supportedFeatures.deleteFileCorsXdr||!this._options.cors.allowXdr)))},_isAllowedExtension:function(e,t){var n=!1;return!e.length||(qq.each(e,function(e,i){if(qq.isString(i)){var o=new RegExp("\\."+i+"$","i");if(null!=t.match(o))return n=!0,!1}}),n)},_itemError:function(e,t,n){function i(e,t){a=a.replace(e,t)}var o,r,a=this._options.messages[e],s=[],l=[].concat(t),u=l[0],c=this._getButtonId(n),d=this._getValidationBase(c);return qq.each(d.allowedExtensions,function(e,t){qq.isString(t)&&s.push(t)}),o=s.join(", ").toLowerCase(),i("{file}",this._options.formatFileName(u)),i("{extensions}",o),i("{sizeLimit}",this._formatSize(d.sizeLimit)),i("{minSizeLimit}",this._formatSize(d.minSizeLimit)),r=a.match(/(\{\w+\})/g),null!==r&&qq.each(r,function(e,t){i(t,l[e])}),this._options.callbacks.onError(null,u,a,void 0),a},_manualRetry:function(e,t){if(this._onBeforeManualRetry(e))return this._netUploadedOrQueued++,this._uploadData.setStatus(e,qq.status.UPLOAD_RETRYING),t?t(e):this._handler.retry(e),!0},_maybeAllComplete:function(e,t){var n=this,i=this._getNotFinished();t===qq.status.UPLOAD_SUCCESSFUL?this._succeededSinceLastAllComplete.push(e):t===qq.status.UPLOAD_FAILED&&this._failedSinceLastAllComplete.push(e),0===i&&(this._succeededSinceLastAllComplete.length||this._failedSinceLastAllComplete.length)&&setTimeout(function(){n._onAllComplete(n._succeededSinceLastAllComplete,n._failedSinceLastAllComplete)},0)},_maybeHandleIos8SafariWorkaround:function(){var e=this;if(this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari())throw setTimeout(function(){window.alert(e._options.messages.unsupportedBrowserIos8Safari)},0),new qq.Error(this._options.messages.unsupportedBrowserIos8Safari)},_maybeParseAndSendUploadError:function(e,t,n,i){if(!n.success)if(i&&200!==i.status&&!n.error)this._options.callbacks.onError(e,t,"XHR returned response code "+i.status,i);else{var o=n.error?n.error:this._options.text.defaultResponseError;this._options.callbacks.onError(e,t,o,i)}},_maybeProcessNextItemAfterOnValidateCallback:function(e,t,n,i,o){var r=this;if(t.length>n)if(e||!this._options.validation.stopOnFirstInvalidFile)setTimeout(function(){var e=r._getValidationDescriptor(t[n]),a=r._getButtonId(t[n].file),s=r._getButton(a);r._handleCheckedCallback({name:"onValidate",callback:qq.bind(r._options.callbacks.onValidate,r,e,s),onSuccess:qq.bind(r._onValidateCallbackSuccess,r,t,n,i,o),onFailure:qq.bind(r._onValidateCallbackFailure,r,t,n,i,o),identifier:"Item '"+e.name+"', size: "+e.size})},0);else if(!e)for(;n0&&this._netUploadedOrQueued+1>n?(this._itemError("retryFailTooManyItems"),!1):(this.log("Retrying upload for '"+t+"' (id: "+e+")..."),!0))):(this.log("'"+e+"' is not a valid file ID","error"),!1)},_onCancel:function(e,t){this._netUploadedOrQueued--,clearTimeout(this._retryTimeouts[e]);var n=qq.indexOf(this._storedIds,e);!this._options.autoUpload&&n>=0&&this._storedIds.splice(n,1),this._uploadData.setStatus(e,qq.status.CANCELED)},_onComplete:function(e,t,n,i){return n.success?(n.thumbnailUrl&&(this._thumbnailUrls[e]=n.thumbnailUrl),this._netUploaded++,this._uploadData.setStatus(e,qq.status.UPLOAD_SUCCESSFUL)):(this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.UPLOAD_FAILED),n[this._options.retry.preventRetryResponseProperty]===!0&&(this._preventRetries[e]=!0)),this._maybeParseAndSendUploadError(e,t,n,i),!!n.success},_onDelete:function(e){this._uploadData.setStatus(e,qq.status.DELETING)},_onDeleteComplete:function(e,t,n){var i=this.getName(e);n?(this._uploadData.setStatus(e,qq.status.DELETE_FAILED),this.log("Delete request for '"+i+"' has failed.","error"),void 0===t.withCredentials?this._options.callbacks.onError(e,i,"Delete request failed",t):this._options.callbacks.onError(e,i,"Delete request failed with response code "+t.status,t)):(this._netUploadedOrQueued--,this._netUploaded--,this._handler.expunge(e),this._uploadData.setStatus(e,qq.status.DELETED),this.log("Delete request for '"+i+"' has succeeded."))},_onInputChange:function(e){var t;if(qq.supportedFeatures.ajaxUploading){for(t=0;t0&&this.addFiles(e);qq.each(this._buttons,function(e,t){t.reset()})},_onProgress:function(e,t,n,i){this._totalProgress&&this._totalProgress.onIndividualProgress(e,n,i)},_onSubmit:function(e,t){},_onSubmitCallbackSuccess:function(e,t){this._onSubmit.apply(this,arguments),this._uploadData.setStatus(e,qq.status.SUBMITTED),this._onSubmitted.apply(this,arguments),this._options.autoUpload?(this._options.callbacks.onSubmitted.apply(this,arguments),this._uploadFile(e)):(this._storeForLater(e),this._options.callbacks.onSubmitted.apply(this,arguments))},_onSubmitDelete:function(e,t,n){var i,o=this.getUuid(e);return t&&(i=qq.bind(t,this,e,o,n)),this._isDeletePossible()?(this._handleCheckedCallback({name:"onSubmitDelete",callback:qq.bind(this._options.callbacks.onSubmitDelete,this,e),onSuccess:i||qq.bind(this._deleteHandler.sendDelete,this,e,o,n),identifier:e}),!0):(this.log("Delete request ignored for ID "+e+", delete feature is disabled or request not possible due to CORS on a user agent that does not support pre-flighting.","warn"),!1)},_onSubmitted:function(e){},_onTotalProgress:function(e,t){this._options.callbacks.onTotalProgress(e,t)},_onUploadPrep:function(e){},_onUpload:function(e,t){this._uploadData.setStatus(e,qq.status.UPLOADING)},_onUploadChunk:function(e,t){},_onUploadStatusChange:function(e,t,n){n===qq.status.PAUSED&&clearTimeout(this._retryTimeouts[e])},_onValidateBatchCallbackFailure:function(e){var t=this;qq.each(e,function(e,n){t._fileOrBlobRejected(n.id)})},_onValidateBatchCallbackSuccess:function(e,t,n,i,o){var r,a=this._currentItemLimit,s=this._netUploadedOrQueued;0===a||s<=a?t.length>0?this._handleCheckedCallback({name:"onValidate",callback:qq.bind(this._options.callbacks.onValidate,this,e[0],o),onSuccess:qq.bind(this._onValidateCallbackSuccess,this,t,0,n,i),onFailure:qq.bind(this._onValidateCallbackFailure,this,t,0,n,i),identifier:"Item '"+t[0].file.name+"', size: "+t[0].file.size}):this._itemError("noFilesError"):(this._onValidateBatchCallbackFailure(t),r=this._options.messages.tooManyItemsError.replace(/\{netItems\}/g,s).replace(/\{itemLimit\}/g,a),this._batchError(r))},_onValidateCallbackFailure:function(e,t,n,i){var o=t+1;this._fileOrBlobRejected(e[t].id,e[t].file.name),this._maybeProcessNextItemAfterOnValidateCallback(!1,e,o,n,i)},_onValidateCallbackSuccess:function(e,t,n,i){var o=this,r=t+1,a=this._getValidationDescriptor(e[t]);this._validateFileOrBlobData(e[t],a).then(function(){o._upload(e[t].id,n,i),o._maybeProcessNextItemAfterOnValidateCallback(!0,e,r,n,i)},function(){o._maybeProcessNextItemAfterOnValidateCallback(!1,e,r,n,i)})},_prepareItemsForUpload:function(e,t,n){if(0===e.length)return void this._itemError("noFilesError");var i=this._getValidationDescriptors(e),o=this._getButtonId(e[0].file),r=this._getButton(o);this._handleCheckedCallback({name:"onValidateBatch",callback:qq.bind(this._options.callbacks.onValidateBatch,this,i,r),onSuccess:qq.bind(this._onValidateBatchCallbackSuccess,this,i,e,t,n,r),onFailure:qq.bind(this._onValidateBatchCallbackFailure,this,e),identifier:"batch validation"})},_preventLeaveInProgress:function(){var e=this;this._disposeSupport.attach(window,"beforeunload",function(t){if(e.getInProgress())return t=t||window.event,t.returnValue=e._options.messages.onLeave,e._options.messages.onLeave})},_refreshSessionData:function(){var e=this,t=this._options.session;qq.Session&&null!=this._options.session.endpoint&&(this._session||(qq.extend(t,{cors:this._options.cors}),t.log=qq.bind(this.log,this),t.addFileRecord=qq.bind(this._addCannedFile,this),this._session=new qq.Session(t)),setTimeout(function(){e._session.refresh().then(function(t,n){e._sessionRequestComplete(),e._options.callbacks.onSessionRequestComplete(t,!0,n)},function(t,n){e._options.callbacks.onSessionRequestComplete(t,!1,n)})},0))},_sessionRequestComplete:function(){},_setSize:function(e,t){this._uploadData.updateSize(e,t),this._totalProgress&&this._totalProgress.onNewSize(e)},_shouldAutoRetry:function(e,t,n){var i=this._uploadData.retrieve({id:e});return!!(!this._preventRetries[e]&&this._options.retry.enableAuto&&i.status!==qq.status.PAUSED&&(void 0===this._autoRetries[e]&&(this._autoRetries[e]=0),this._autoRetries[e]0&&s.sizeLimit&&r>s.sizeLimit?(this._itemError("sizeError",o,i),l.failure()):r>0&&r=0}function n(e){var t=!1;return qq.each(t,function(e,n){if(qq.indexOf(["Accept","Accept-Language","Content-Language","Content-Type"],n)<0)return t=!0,!1}),t}function i(e){return S.cors.expected&&void 0===e.withCredentials}function o(){var e;return(window.XMLHttpRequest||window.ActiveXObject)&&(e=qq.createXhrInstance(),void 0===e.withCredentials&&(e=new XDomainRequest,e.onload=function(){},e.onerror=function(){},e.ontimeout=function(){},e.onprogress=function(){})),e}function r(e,t){var n=y[e].xhr;return n||(n=t?t:S.cors.expected?o():qq.createXhrInstance(),y[e].xhr=n),n}function a(e){var t,n=qq.indexOf(v,e),i=S.maxConnections;delete y[e],v.splice(n,1),v.length>=i&&n=0?o.send(qq.obj2url(s,"")):s&&S.contentType&&S.contentType.toLowerCase().indexOf("application/json")>=0?o.send(JSON.stringify(s)):o.send(s),o}function c(e,t,n){var i=S.endpointStore.get(e),o=y[e].addToPath;return void 0!=o&&(i+="/"+o),b&&t&&(i=qq.obj2url(t,i)),n&&(i=qq.obj2url(n,i)),i}function d(e){return function(){4===r(e).readyState&&s(e)}}function p(e){var t=S.onProgress;t&&(r(e).upload.onprogress=function(n){n.lengthComputable&&t(e,n.loaded,n.total)})}function q(e){return function(){s(e)}}function h(e){return function(){s(e,!0)}}function f(e){var o=r(e),a=S.customHeaders,s=y[e].additionalHeaders||{},l=S.method,u={};i(o)||(S.acceptHeader&&o.setRequestHeader("Accept",S.acceptHeader),S.allowXRequestedWithAndCacheControl&&(S.cors.expected&&t()&&!n(a)||(o.setRequestHeader("X-Requested-With","XMLHttpRequest"),o.setRequestHeader("Cache-Control","no-cache"))),!S.contentType||"POST"!==l&&"PUT"!==l||o.setRequestHeader("Content-Type",S.contentType),qq.extend(u,qq.isFunction(a)?a(e):a),qq.extend(u,s),qq.each(u,function(e,t){o.setRequestHeader(e,t)}))}function m(e){return qq.indexOf(S.successfulResponseCodes[S.method],e)>=0}function g(e,t,n,i,o,r,a){y[e]={addToPath:n,additionalParams:i,additionalQueryParams:o,additionalHeaders:r,payload:a};var s=v.push(e);if(s<=S.maxConnections)return u(e,t)}var _,b,v=[],y={},S={acceptHeader:null,validMethods:["PATCH","POST","PUT"],method:"POST",contentType:"application/x-www-form-urlencoded",maxConnections:3,customHeaders:{},endpointStore:{},paramsStore:{},mandatedParams:{},allowXRequestedWithAndCacheControl:!0,successfulResponseCodes:{DELETE:[200,202,204],PATCH:[200,201,202,203,204],POST:[200,201,202,203,204],PUT:[200,201,202,203,204],GET:[200]},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onSend:function(e){},onComplete:function(e,t,n){},onProgress:null};if(qq.extend(S,e),_=S.log,qq.indexOf(S.validMethods,S.method)<0)throw new Error("'"+S.method+"' is not a supported method for this type of request!");b="GET"===S.method||"DELETE"===S.method,qq.extend(this,{initTransport:function(e){var t,n,i,o,r,a;return{withPath:function(e){return t=e,this},withParams:function(e){return n=e,this},withQueryParams:function(e){return a=e,this},withHeaders:function(e){return i=e,this},withPayload:function(e){return o=e,this},withCacheBuster:function(){return r=!0,this},send:function(s){return r&&qq.indexOf(["GET","DELETE"],S.method)>=0&&(n.qqtimestamp=(new Date).getTime()),g(e,s,t,n,a,i,o)}}},canceled:function(e){a(e)}})},qq.UploadHandler=function(e){"use strict";var t=e.proxy,n={},i=t.onCancel,o=t.getName;qq.extend(this,{add:function(e,t){n[e]=t,n[e].temp={}},cancel:function(e){var t=this,r=new qq.Promise,a=i(e,o(e),r);a.then(function(){t.isValid(e)&&(n[e].canceled=!0,t.expunge(e)),r.success()})},expunge:function(e){delete n[e]},getThirdPartyFileId:function(e){return n[e].key},isValid:function(e){return void 0!==n[e]},reset:function(){n={}},_getFileState:function(e){return n[e]},_setThirdPartyFileId:function(e,t){n[e].key=t},_wasCanceled:function(e){return!!n[e].canceled}})},qq.UploadHandlerController=function(e,t){"use strict";var n,i,o,r=this,a=!1,s=!1,l={paramsStore:{},maxConnections:3,chunking:{enabled:!1,multiple:{enabled:!1}},log:function(e,t){},onProgress:function(e,t,n,i){},onComplete:function(e,t,n,i){},onCancel:function(e,t){},onUploadPrep:function(e){},onUpload:function(e,t){},onUploadChunk:function(e,t,n){},onUploadChunkSuccess:function(e,t,n,i){},onAutoRetry:function(e,t,n,i){},onResume:function(e,t,n){},onUuidChanged:function(e,t){},getName:function(e){},setSize:function(e,t){},isQueued:function(e){},getIdsInProxyGroup:function(e){},getIdsInBatch:function(e){}},u={done:function(e,t,n,i){var r=o._getChunkData(e,t);o._getFileState(e).attemptingResume=!1,delete o._getFileState(e).temp.chunkProgress[t],o._getFileState(e).loaded+=r.size,l.onUploadChunkSuccess(e,o._getChunkDataForCallback(r),n,i)},finalize:function(e){var t=l.getSize(e),n=l.getName(e);i("All chunks have been uploaded for "+e+" - finalizing...."),o.finalizeChunks(e).then(function(r,a){i("Finalize successful for "+e);var s=p.normalizeResponse(r,!0);l.onProgress(e,n,t,t),o._maybeDeletePersistedChunkData(e),p.cleanup(e,s,a)},function(t,o){var r=p.normalizeResponse(t,!1);i("Problem finalizing chunks for file ID "+e+" - "+r.error,"error"),r.reset&&u.reset(e),l.onAutoRetry(e,n,r,o)||p.cleanup(e,r,o)})},handleFailure:function(e,t,n,r){var a=l.getName(t);i("Chunked upload request failed for "+t+", chunk "+e),o.clearCachedChunk(t,e);var d,q=p.normalizeResponse(n,!1);q.reset?u.reset(t):(d=qq.indexOf(o._getFileState(t).chunking.inProgress,e),d>=0&&(o._getFileState(t).chunking.inProgress.splice(d,1),o._getFileState(t).chunking.remaining.unshift(e))),o._getFileState(t).temp.ignoreFailure||(s&&(o._getFileState(t).temp.ignoreFailure=!0,i(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.",JSON.stringify(Object.keys(o._getXhrs(t))),JSON.stringify(o._getFileState(t).chunking.inProgress))),qq.each(o._getXhrs(t),function(e,n){i(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ",t,e,n.readyState)),n.abort(),n._cancelled=!0}),o.moveInProgressToRemaining(t),c.free(t,!0)),l.onAutoRetry(t,a,q,r)||p.cleanup(t,q,r))},hasMoreParts:function(e){return!!o._getFileState(e).chunking.remaining.length},nextPart:function(e){var t=o._getFileState(e).chunking.remaining.shift();return t>=o._getTotalChunks(e)&&(t=null),t},reset:function(e){i("Server or callback has ordered chunking effort to be restarted on next attempt for item ID "+e,"error"),o._maybeDeletePersistedChunkData(e),o.reevaluateChunking(e),o._getFileState(e).loaded=0},sendNext:function(e){var t=l.getSize(e),n=l.getName(e),r=u.nextPart(e),a=o._getChunkData(e,r),d=o._getFileState(e).attemptingResume,q=o._getFileState(e).chunking.inProgress||[];null==o._getFileState(e).loaded&&(o._getFileState(e).loaded=0),d&&l.onResume(e,n,a)===!1&&(u.reset(e),r=u.nextPart(e),a=o._getChunkData(e,r),d=!1),null==r&&0===q.length?u.finalize(e):(i(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.",e,r,a.start+1,a.end,t)),l.onUploadChunk(e,n,o._getChunkDataForCallback(a)),q.push(r),o._getFileState(e).chunking.inProgress=q,s&&c.open(e,r),s&&c.available()&&o._getFileState(e).chunking.remaining.length&&u.sendNext(e),0===a.blob.size?(i(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.",r,e),"error"),u.handleFailure(r,e,"File is no longer available",null)):o.uploadChunk(e,r,d).then(function(t,n){i("Chunked upload request succeeded for "+e+", chunk "+r),o.clearCachedChunk(e,r);var a=o._getFileState(e).chunking.inProgress||[],s=p.normalizeResponse(t,!0),l=qq.indexOf(a,r);i(qq.format("Chunk {} for file {} uploaded successfully.",r,e)),u.done(e,r,s,n),l>=0&&a.splice(l,1),o._maybePersistChunkedState(e),u.hasMoreParts(e)||0!==a.length?u.hasMoreParts(e)?u.sendNext(e):i(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}",e,JSON.stringify(a))):u.finalize(e)},function(t,n){u.handleFailure(r,e,t,n)}).done(function(){o.clearXhr(e,r)}))}},c={_open:[],_openChunks:{},_waiting:[],available:function(){var e=l.maxConnections,t=0,n=0;return qq.each(c._openChunks,function(e,i){t++,n+=i.length}),e-(c._open.length-t+n)},free:function(e,t){var n,r=!t,a=qq.indexOf(c._waiting,e),s=qq.indexOf(c._open,e);delete c._openChunks[e],p.getProxyOrBlob(e)instanceof qq.BlobProxy&&(i("Generated blob upload has ended for "+e+", disposing generated blob."),delete o._getFileState(e).file),a>=0?c._waiting.splice(a,1):r&&s>=0&&(c._open.splice(s,1),n=c._waiting.shift(),n>=0&&(c._open.push(n),p.start(n)))},getWaitingOrConnected:function(){var e=[];return qq.each(c._openChunks,function(t,n){n&&n.length&&e.push(parseInt(t));
+}),qq.each(c._open,function(t,n){c._openChunks[n]||e.push(parseInt(n))}),e=e.concat(c._waiting)},isUsingConnection:function(e){return qq.indexOf(c._open,e)>=0},open:function(e,t){return null==t&&c._waiting.push(e),!!c.available()&&(null==t?(c._waiting.pop(),c._open.push(e)):!function(){var n=c._openChunks[e]||[];n.push(t),c._openChunks[e]=n}(),!0)},reset:function(){c._waiting=[],c._open=[]}},d={send:function(e,t){o._getFileState(e).loaded=0,i("Sending simple upload request for "+e),o.uploadFile(e).then(function(n,o){i("Simple upload request succeeded for "+e);var r=p.normalizeResponse(n,!0),a=l.getSize(e);l.onProgress(e,t,a,a),p.maybeNewUuid(e,r),p.cleanup(e,r,o)},function(n,o){i("Simple upload request failed for "+e);var r=p.normalizeResponse(n,!1);l.onAutoRetry(e,t,r,o)||p.cleanup(e,r,o)})}},p={cancel:function(e){i("Cancelling "+e),l.paramsStore.remove(e),c.free(e)},cleanup:function(e,t,n){var i=l.getName(e);l.onComplete(e,i,t,n),o._getFileState(e)&&o._clearXhrs&&o._clearXhrs(e),c.free(e)},getProxyOrBlob:function(e){return o.getProxy&&o.getProxy(e)||o.getFile&&o.getFile(e)},initHandler:function(){var e=t?qq[t]:qq.traditional,n=qq.supportedFeatures.ajaxUploading?"Xhr":"Form";o=new e[n+"UploadHandler"](l,{getDataByUuid:l.getDataByUuid,getName:l.getName,getSize:l.getSize,getUuid:l.getUuid,log:i,onCancel:l.onCancel,onProgress:l.onProgress,onUuidChanged:l.onUuidChanged}),o._removeExpiredChunkingRecords&&o._removeExpiredChunkingRecords()},isDeferredEligibleForUpload:function(e){return l.isQueued(e)},maybeDefer:function(e,t){return t&&!o.getFile(e)&&t instanceof qq.BlobProxy?(l.onUploadPrep(e),i("Attempting to generate a blob on-demand for "+e),t.create().then(function(t){i("Generated an on-demand blob for "+e),o.updateBlob(e,t),l.setSize(e,t.size),o.reevaluateChunking(e),p.maybeSendDeferredFiles(e)},function(t){var o={};t&&(o.error=t),i(qq.format("Failed to generate blob for ID {}. Error message: {}.",e,t),"error"),l.onComplete(e,l.getName(e),qq.extend(o,n),null),p.maybeSendDeferredFiles(e),c.free(e)}),!1):p.maybeSendDeferredFiles(e)},maybeSendDeferredFiles:function(e){var t=l.getIdsInProxyGroup(e),n=!1;return t&&t.length?(i("Maybe ready to upload proxy group file "+e),qq.each(t,function(t,i){if(p.isDeferredEligibleForUpload(i)&&o.getFile(i))n=i===e,p.now(i);else if(p.isDeferredEligibleForUpload(i))return!1})):(n=!0,p.now(e)),n},maybeNewUuid:function(e,t){void 0!==t.newUuid&&l.onUuidChanged(e,t.newUuid)},normalizeResponse:function(e,t){var n=e;return qq.isObject(e)||(n={},qq.isString(e)&&!t&&(n.error=e)),n.success=t,n},now:function(e){var t=l.getName(e);if(!r.isValid(e))throw new qq.Error(e+" is not a valid file ID to upload!");l.onUpload(e,t),a&&o._shouldChunkThisFile(e)?u.sendNext(e):d.send(e,t)},start:function(e){var t=p.getProxyOrBlob(e);return t?p.maybeDefer(e,t):(p.now(e),!0)}};qq.extend(this,{add:function(e,t){o.add.apply(this,arguments)},upload:function(e){return!!c.open(e)&&p.start(e)},retry:function(e){return s&&(o._getFileState(e).temp.ignoreFailure=!1),c.isUsingConnection(e)?p.start(e):r.upload(e)},cancel:function(e){var t=o.cancel(e);qq.isGenericPromise(t)?t.then(function(){p.cancel(e)}):t!==!1&&p.cancel(e)},cancelAll:function(){var e,t=c.getWaitingOrConnected();if(t.length)for(e=t.length-1;e>=0;e--)r.cancel(t[e]);c.reset()},getFile:function(e){return o.getProxy&&o.getProxy(e)?o.getProxy(e).referenceBlob:o.getFile&&o.getFile(e)},isProxied:function(e){return!(!o.getProxy||!o.getProxy(e))},getInput:function(e){if(o.getInput)return o.getInput(e)},reset:function(){i("Resetting upload handler"),r.cancelAll(),c.reset(),o.reset()},expunge:function(e){if(r.isValid(e))return o.expunge(e)},isValid:function(e){return o.isValid(e)},getResumableFilesData:function(){return o.getResumableFilesData?o.getResumableFilesData():[]},getThirdPartyFileId:function(e){if(r.isValid(e))return o.getThirdPartyFileId(e)},pause:function(e){return!!(r.isResumable(e)&&o.pause&&r.isValid(e)&&o.pause(e))&&(c.free(e),o.moveInProgressToRemaining(e),!0)},isResumable:function(e){return!!o.isResumable&&o.isResumable(e)}}),qq.extend(l,e),i=l.log,a=l.chunking.enabled&&qq.supportedFeatures.chunking,s=a&&l.chunking.concurrent.enabled,n=function(){var e={};return e[l.preventRetryParam]=!0,e}(),p.initHandler()},qq.WindowReceiveMessage=function(e){"use strict";var t={log:function(e,t){}},n={};qq.extend(t,e),qq.extend(this,{receiveMessage:function(e,t){var i=function(e){t(e.data)};window.postMessage?n[e]=qq(window).attach("message",i):log("iframe message passing not supported in this browser!","error")},stopReceivingMessages:function(e){if(window.postMessage){var t=n[e];t&&t()}}})},qq.FormUploadHandler=function(e){"use strict";function t(e){delete c[e],p&&(clearTimeout(d[e]),delete d[e],m.stopReceivingMessages(e));var t=document.getElementById(a._getIframeName(e));t&&(t.setAttribute("src","javascript:false;"),qq(t).remove())}function n(e){return e.split("_")[0]}function i(e){var t=qq.toElement("");return t.setAttribute("id",e),t.style.display="none",document.body.appendChild(t),t}function o(e,t){var i=e.id,o=n(i),r=h(o);u[r]=t,c[o]=qq(e).attach("load",function(){a.getInput(o)&&(f("Received iframe load event for CORS upload request (iframe name "+i+")"),d[i]=setTimeout(function(){var e="No valid message received from loaded iframe for iframe name "+i;f(e,"error"),t({error:e})},1e3))}),m.receiveMessage(i,function(e){f("Received the following window message: '"+e+"'");var t,o=(n(i),a._parseJsonResponse(e)),r=o.uuid;r&&u[r]?(f("Handling response for iframe name "+i),clearTimeout(d[i]),delete d[i],a._detachLoadEvent(i),t=u[r],delete u[r],m.stopReceivingMessages(i),t(o)):r||f("'"+e+"' does not contain a UUID - ignoring.")})}var r=e.options,a=this,s=e.proxy,l=qq.getUniqueId(),u={},c={},d={},p=r.isCors,q=r.inputName,h=s.getUuid,f=s.log,m=new qq.WindowReceiveMessage({log:f});qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,n){e.add(t,{input:n}),n.setAttribute("name",q),n.parentNode&&qq(n).remove()},expunge:function(n){t(n),e.expunge(n)},isValid:function(t){return e.isValid(t)&&void 0!==a._getFileState(t).input}}}),qq.extend(this,{getInput:function(e){return a._getFileState(e).input},_attachLoadEvent:function(e,t){var n;p?o(e,t):c[e.id]=qq(e).attach("load",function(){if(f("Received response for "+e.id),e.parentNode){try{if(e.contentDocument&&e.contentDocument.body&&"false"==e.contentDocument.body.innerHTML)return}catch(e){f("Error when attempting to access iframe during handling of upload response ("+e.message+")","error"),n={success:!1}}t(n)}})},_createIframe:function(e){var t=a._getIframeName(e);return i(t)},_detachLoadEvent:function(e){void 0!==c[e]&&(c[e](),delete c[e])},_getIframeName:function(e){return e+"_"+l},_initFormForUpload:function(e){var t=e.method,n=e.endpoint,i=e.params,o=e.paramsInBody,r=e.targetName,a=qq.toElement(""),s=n;return o?qq.obj2Inputs(i,a):s=qq.obj2url(i,n),a.setAttribute("action",s),a.setAttribute("target",r),a.style.display="none",document.body.appendChild(a),a},_parseJsonResponse:function(e){var t={};try{t=qq.parseJson(e)}catch(e){f("Error when attempting to parse iframe upload response ("+e.message+")","error")}return t}})},qq.XhrUploadHandler=function(e){"use strict";function t(e){qq.each(n._getXhrs(e),function(t,i){var o=n._getAjaxRequester(e,t);i.onreadystatechange=null,i.upload.onprogress=null,i.abort(),o&&o.canceled&&o.canceled(e)})}var n=this,i=e.options.namespace,o=e.proxy,r=e.options.chunking,a=e.options.resume,s=r&&e.options.chunking.enabled&&qq.supportedFeatures.chunking,l=a&&e.options.resume.enabled&&s&&qq.supportedFeatures.resume,u=o.getName,c=o.getSize,d=o.getUuid,p=o.getEndpoint,q=o.getDataByUuid,h=o.onUuidChanged,f=o.onProgress,m=o.log;qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,i){if(qq.isFile(i)||qq.isBlob(i))e.add(t,{file:i});else{if(!(i instanceof qq.BlobProxy))throw new Error("Passed obj is not a File, Blob, or proxy");e.add(t,{proxy:i})}n._initTempState(t),l&&n._maybePrepareForResume(t)},expunge:function(i){t(i),n._maybeDeletePersistedChunkData(i),n._clearXhrs(i),e.expunge(i)}}}),qq.extend(this,{clearCachedChunk:function(e,t){delete n._getFileState(e).temp.cachedChunks[t]},clearXhr:function(e,t){var i=n._getFileState(e).temp;i.xhrs&&delete i.xhrs[t],i.ajaxRequesters&&delete i.ajaxRequesters[t]},finalizeChunks:function(e,t){var i=n._getTotalChunks(e)-1,o=n._getXhr(e,i);return t?(new qq.Promise).success(t(o),o):(new qq.Promise).success({},o)},getFile:function(e){return n.isValid(e)&&n._getFileState(e).file},getProxy:function(e){return n.isValid(e)&&n._getFileState(e).proxy},getResumableFilesData:function(){var e=[];return n._iterateResumeRecords(function(t,i){n.moveInProgressToRemaining(null,i.chunking.inProgress,i.chunking.remaining);var o={name:i.name,remaining:i.chunking.remaining,size:i.size,uuid:i.uuid};i.key&&(o.key=i.key),e.push(o)}),e},isResumable:function(e){return!!r&&n.isValid(e)&&!n._getFileState(e).notResumable},moveInProgressToRemaining:function(e,t,i){var o=t||n._getFileState(e).chunking.inProgress,r=i||n._getFileState(e).chunking.remaining;o&&(m(qq.format("Moving these chunks from in-progress {}, to remaining.",JSON.stringify(o))),o.reverse(),qq.each(o,function(e,t){r.unshift(t)}),o.length=0)},pause:function(e){if(n.isValid(e))return m(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.",e,u(e))),n._getFileState(e).paused=!0,t(e),!0},reevaluateChunking:function(e){if(r&&n.isValid(e)){var t,i,o=n._getFileState(e);if(delete o.chunking,o.chunking={},t=n._getTotalChunks(e),t>1||r.mandatory){for(o.chunking.enabled=!0,o.chunking.parts=t,o.chunking.remaining=[],i=0;i=o?o:s+i,u=n._getTotalChunks(e),d=this._getFileState(e).temp.cachedChunks,p=d[t]||qq.sliceBlob(a,s,l);return d[t]=p,{part:t,start:s,end:l,count:u,blob:p,size:l-s}},_getChunkDataForCallback:function(e){return{partIndex:e.part,startByte:e.start+1,endByte:e.end,totalParts:e.count}},_getLocalStorageId:function(e){var t="5.0",n=u(e),o=c(e),a=r.partSize,s=p(e);return qq.format("qq{}resume{}-{}-{}-{}-{}",i,t,n,o,a,s)},_getMimeType:function(e){return n.getFile(e).type},_getPersistableData:function(e){return n._getFileState(e).chunking},_getTotalChunks:function(e){if(r){var t=c(e),n=r.partSize;return Math.ceil(t/n)}},_getXhr:function(e,t){var i=null==t?-1:t;return n._getFileState(e).temp.xhrs[i]},_getXhrs:function(e){return n._getFileState(e).temp.xhrs},_iterateResumeRecords:function(e){l&&qq.each(localStorage,function(t,n){if(0===t.indexOf(qq.format("qq{}resume",i))){var o=JSON.parse(n);e(t,o)}})},_initTempState:function(e){n._getFileState(e).temp={ajaxRequesters:{},chunkProgress:{},xhrs:{},cachedChunks:{}}},_markNotResumable:function(e){n._getFileState(e).notResumable=!0},_maybeDeletePersistedChunkData:function(e){var t;return!!(l&&n.isResumable(e)&&(t=n._getLocalStorageId(e),t&&localStorage.getItem(t)))&&(localStorage.removeItem(t),!0)},_maybePrepareForResume:function(e){var t,i,o=n._getFileState(e);l&&void 0===o.key&&(t=n._getLocalStorageId(e),i=localStorage.getItem(t),i&&(i=JSON.parse(i),q(i.uuid)?n._markNotResumable(e):(m(qq.format("Identified file with ID {} and name of {} as resumable.",e,u(e))),h(e,i.uuid),o.key=i.key,o.chunking=i.chunking,o.loaded=i.loaded,o.attemptingResume=!0,n.moveInProgressToRemaining(e))))},_maybePersistChunkedState:function(e){var t,i,o=n._getFileState(e);if(l&&n.isResumable(e)){t=n._getLocalStorageId(e),i={name:u(e),size:c(e),uuid:d(e),key:o.key,chunking:o.chunking,loaded:o.loaded,lastUpdated:Date.now()};try{localStorage.setItem(t,JSON.stringify(i))}catch(t){m(qq.format("Unable to save resume data for '{}' due to error: '{}'.",e,t.toString()),"warn")}}},_registerProgressHandler:function(e,t,i){var o=n._getXhr(e,t),r=u(e),a={simple:function(t,n){var i=c(e);t===n?f(e,r,i,i):f(e,r,t>=i?i-1:t,i)},chunked:function(o,a){var s=n._getFileState(e).temp.chunkProgress,l=n._getFileState(e).loaded,u=o,d=a,p=c(e),q=u-(d-i),h=l;s[t]=q,qq.each(s,function(e,t){h+=t}),f(e,r,h,p)}};o.upload.onprogress=function(e){if(e.lengthComputable){var t=null==i?"simple":"chunked";a[t](e.loaded,e.total)}}},_registerXhr:function(e,t,i,o){var r=null==t?-1:t,a=n._getFileState(e).temp;return a.xhrs=a.xhrs||{},a.ajaxRequesters=a.ajaxRequesters||{},a.xhrs[r]=i,o&&(a.ajaxRequesters[r]=o),i},_removeExpiredChunkingRecords:function(){var e=a.recordsExpireIn;n._iterateResumeRecords(function(t,n){var i=new Date(n.lastUpdated);i.setDate(i.getDate()+e),i.getTime()<=Date.now()&&(m("Removing expired resume record with key "+t),localStorage.removeItem(t))})},_shouldChunkThisFile:function(e){var t=n._getFileState(e);return t.chunking||n.reevaluateChunking(e),t.chunking.enabled}})},qq.DeleteFileAjaxRequester=function(e){"use strict";function t(){return"POST"===i.method.toUpperCase()?{_method:"DELETE"}:{}}var n,i={method:"DELETE",uuidParamName:"qquuid",endpointStore:{},maxConnections:3,customHeaders:function(e){return{}},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onDelete:function(e){},onDeleteComplete:function(e,t,n){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["POST","DELETE"],method:i.method,endpointStore:i.endpointStore,paramsStore:i.paramsStore,mandatedParams:t(),maxConnections:i.maxConnections,customHeaders:function(e){return i.customHeaders.get(e)},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete,cors:i.cors})),qq.extend(this,{sendDelete:function(e,t,o){var r=o||{};i.log("Submitting delete file request for "+e),"DELETE"===i.method?n.initTransport(e).withPath(t).withParams(r).send():(r[i.uuidParamName]=t,n.initTransport(e).withParams(r).send())}})},function(){function e(e){var t,n=e.naturalWidth,i=e.naturalHeight,o=document.createElement("canvas");return n*i>1048576&&(o.width=o.height=1,t=o.getContext("2d"),t.drawImage(e,-n+1,0),0===t.getImageData(0,0,1,1).data[3])}function t(e,t,n){var i,o,r,a,s=document.createElement("canvas"),l=0,u=n,c=n;for(s.width=1,s.height=n,i=s.getContext("2d"),i.drawImage(e,0,0),o=i.getImageData(0,0,1,n).data;c>l;)r=o[4*(c-1)+3],0===r?u=c:l=c,c=u+l>>1;return a=c/n,0===a?1:a}function n(e,t,n,i){var r=document.createElement("canvas"),a=n.mime||"image/jpeg",s=new qq.Promise;return o(e,t,r,n,i).then(function(){s.success(r.toDataURL(a,n.quality||.8))}),s}function i(e){var t=5241e3;if(!qq.ios())throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");if(e.origHeight*e.origWidth>t)return{newHeight:Math.round(Math.sqrt(t*(e.origHeight/e.origWidth))),newWidth:Math.round(Math.sqrt(t*(e.origWidth/e.origHeight)))}}function o(n,o,s,l,u){var c,d=n.naturalWidth,p=n.naturalHeight,q=l.width,h=l.height,f=s.getContext("2d"),m=new qq.Promise;return f.save(),l.resize?r({blob:o,canvas:s,image:n,imageHeight:p,imageWidth:d,orientation:l.orientation,resize:l.resize,targetHeight:h,targetWidth:q}):(qq.supportedFeatures.unlimitedScaledImageSize||(c=i({origWidth:q,origHeight:h}),c&&(qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h",q,h,c.newWidth,c.newHeight),"warn"),q=c.newWidth,h=c.newHeight)),a(s,q,h,l.orientation),qq.ios()?!function(){e(n)&&(d/=2,p/=2);var i,o,r,a=1024,s=document.createElement("canvas"),l=u?t(n,d,p):1,c=Math.ceil(a*q/d),m=Math.ceil(a*h/p/l),g=0,_=0;for(s.width=s.height=a,i=s.getContext("2d");gc&&(l=c,u=s*l/a<<0),d&&u>d&&(u=d,l=a*u/s<<0),i={width:l,height:u},qq.each(t,function(e,t){i[e]=t}),"img"===q?!function(){var t=e.src;n(r.srcImage,r.blob,i,p).then(function(n){e.src=n,t===e.src&&e.onload()})}():"canvas"===q&&o(this.srcImage,this.blob,e,i,p),void("function"==typeof this.onrender&&this.onrender(e)))},qq.MegaPixImage=s}(),qq.ImageGenerator=function(e){"use strict";function t(e){return"img"===e.tagName.toLowerCase()}function n(e){return"canvas"===e.tagName.toLowerCase()}function i(){return void 0!==(new Image).crossOrigin}function o(){var e=document.createElement("canvas");return e.getContext&&e.getContext("2d")}function r(e){var t=e.split("/"),n=t[t.length-1].split("?")[0],i=qq.getExtension(n);switch(i=i&&i.toLowerCase()){case"jpeg":case"jpg":return"image/jpeg";case"png":return"image/png";case"bmp":return"image/bmp";case"gif":return"image/gif";case"tiff":case"tif":return"image/tiff"}}function a(e){var t,n,i,o=document.createElement("a");return o.href=e,t=o.protocol,i=o.port,n=o.hostname,t.toLowerCase()!==window.location.protocol.toLowerCase()||(n.toLowerCase()!==window.location.hostname.toLowerCase()||i!==window.location.port&&!qq.ie())}function s(t,n){t.onload=function(){t.onload=null,t.onerror=null,n.success(t)},t.onerror=function(){t.onload=null,t.onerror=null,e("Problem drawing thumbnail!","error"),n.failure(t,"Problem drawing thumbnail!")}}function l(e,t){e.qqImageRendered=function(){t.success(e)}}function u(i,o){var r=t(i)||n(i);return t(i)?s(i,o):n(i)?l(i,o):(o.failure(i),e(qq.format("Element container of type {} is not supported!",i.tagName),"error")),r}function c(t,n,i){var o=new qq.Promise,r=new qq.Identify(t,e),a=i.maxSize,s=null==i.orient||i.orient,l=function(){n.onerror=null,n.onload=null,e("Could not render preview, file may be too large!","error"),o.failure(n,"Browser cannot render image!")};return r.isPreviewable().then(function(r){var c={parse:function(){return(new qq.Promise).success()}},d=s?new qq.Exif(t,e):c,p=new qq.MegaPixImage(t,l);u(n,o)&&d.parse().then(function(e){var t=e&&e.Orientation;p.render(n,{maxWidth:a,maxHeight:a,orientation:t,mime:r,resize:i.customResizeFunction})},function(t){e(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.",t)),p.render(n,{maxWidth:a,maxHeight:a,mime:r,resize:i.customResizeFunction})})},function(){e("Not previewable"),o.failure(n,"Not previewable")}),o}function d(e,t,n,i,o){var s=new Image,l=new qq.Promise;u(s,l),a(e)&&(s.crossOrigin="anonymous"),s.src=e,l.then(function(){u(t,n);var a=new qq.MegaPixImage(s);a.render(t,{maxWidth:i,maxHeight:i,mime:r(e),resize:o})},n.failure)}function p(e,t,n,i){u(t,n),qq(t).css({maxWidth:i+"px",maxHeight:i+"px"}),t.src=e}function q(e,r,s){var l=new qq.Promise,c=s.scale,q=c?s.maxSize:null;return c&&t(r)?o()?a(e)&&!i()?p(e,r,l,q):d(e,r,l,q):p(e,r,l,q):n(r)?d(e,r,l,q):u(r,l)&&(r.src=e),l}qq.extend(this,{generate:function(t,n,i){return qq.isString(t)?(e("Attempting to update thumbnail based on server response."),q(t,n,i||{})):(e("Attempting to draw client-side image preview."),c(t,n,i||{}))}}),this._testing={},this._testing.isImg=t,this._testing.isCanvas=n,this._testing.isCrossOrigin=a,this._testing.determineMimeOfFileName=r},qq.Exif=function(e,t){"use strict";function n(e){for(var t=0,n=0;e.length>0;)t+=parseInt(e.substring(0,2),16)*Math.pow(2,n),e=e.substring(2,e.length),n+=8;return t}function i(t,n){var o=t,r=n;return void 0===o&&(o=2,r=new qq.Promise),qq.readBlobToHex(e,o,4).then(function(e){var t,n=/^ffe([0-9])/.exec(e);n?"1"!==n[1]?(t=parseInt(e.slice(4,8),16),i(o+t+2,r)):r.success(o):r.failure("No EXIF header to be found!")}),r}function o(){var t=new qq.Promise;return qq.readBlobToHex(e,0,6).then(function(e){0!==e.indexOf("ffd8")?t.failure("Not a valid JPEG!"):i().then(function(e){t.success(e)},function(e){t.failure(e)})}),t}function r(t){var n=new qq.Promise;return qq.readBlobToHex(e,t+10,2).then(function(e){n.success("4949"===e)}),n}function a(t,i){var o=new qq.Promise;return qq.readBlobToHex(e,t+18,2).then(function(e){return i?o.success(n(e)):void o.success(parseInt(e,16))}),o}function s(t,n){var i=t+20,o=12*n;return qq.readBlobToHex(e,i,o)}function l(e){for(var t=[],n=0;n+24<=e.length;)t.push(e.slice(n,n+24)),n+=24;return t}function u(e,t){var i=16,o=qq.extend([],c),r={};return qq.each(t,function(t,a){var s,l,u,c=a.slice(0,4),p=e?n(c):parseInt(c,16),q=o.indexOf(p);if(q>=0&&(l=d[p].name,u=d[p].bytes,s=a.slice(i,i+2*u),r[l]=e?n(s):parseInt(s,16),o.splice(q,1)),0===o.length)return!1}),r}var c=[274],d={274:{name:"Orientation",bytes:2}};qq.extend(this,{parse:function(){var n=new qq.Promise,i=function(e){t(qq.format("EXIF header parse failed: '{}' ",e)),n.failure(e)};return o().then(function(o){t(qq.format("Moving forward with EXIF header parsing for '{}'",void 0===e.name?"blob":e.name)),r(o).then(function(e){t(qq.format("EXIF Byte order is {} endian",e?"little":"big")),a(o,e).then(function(r){t(qq.format("Found {} APP1 directory entries",r)),s(o,r).then(function(i){var o=l(i),r=u(e,o);t("Successfully parsed some EXIF tags"),n.success(r)},i)},i)},i)},i),n}}),this._testing={},this._testing.parseLittleEndian=n},qq.Identify=function(e,t){"use strict";function n(e,t){var n=!1,i=[].concat(e);return qq.each(i,function(e,i){if(0===t.indexOf(i))return n=!0,!1}),n}qq.extend(this,{isPreviewable:function(){var i=this,o=new qq.Promise,r=!1,a=void 0===e.name?"blob":e.name;return t(qq.format("Attempting to determine if {} can be rendered in this browser",a)),t("First pass: check type attribute of blob object."),this.isPreviewableSync()?(t("Second pass: check for magic bytes in file header."),qq.readBlobToHex(e,0,4).then(function(e){qq.each(i.PREVIEWABLE_MIME_TYPES,function(t,i){if(n(i,e))return("image/tiff"!==t||qq.supportedFeatures.tiffPreviews)&&(r=!0,o.success(t)),!1}),t(qq.format("'{}' is {} able to be rendered in this browser",a,r?"":"NOT")),r||o.failure()},function(){t("Error reading file w/ name '"+a+"'. Not able to be rendered in this browser."),o.failure()})):o.failure(),o},isPreviewableSync:function(){var n=e.type,i=qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES),n)>=0,o=!1,r=void 0===e.name?"blob":e.name;return i&&(o="image/tiff"!==n||qq.supportedFeatures.tiffPreviews),!o&&t(r+" is not previewable in this browser per the blob's type attr"),o}})},qq.Identify.prototype.PREVIEWABLE_MIME_TYPES={"image/jpeg":"ffd8ff","image/gif":"474946","image/png":"89504e","image/bmp":"424d","image/tiff":["49492a00","4d4d002a"]},qq.ImageValidation=function(e,t){"use strict";function n(e){var t=!1;return qq.each(e,function(e,n){if(n>0)return t=!0,!1}),t}function i(){var n=new qq.Promise;return new qq.Identify(e,t).isPreviewable().then(function(){var i=new Image,o=window.URL&&window.URL.createObjectURL?window.URL:window.webkitURL&&window.webkitURL.createObjectURL?window.webkitURL:null;o?(i.onerror=function(){t("Cannot determine dimensions for image. May be too large.","error"),n.failure()},i.onload=function(){n.success({width:this.width,height:this.height})},i.src=o.createObjectURL(e)):(t("No createObjectURL function available to generate image URL!","error"),n.failure())},n.failure),n}function o(e,t){var n;return qq.each(e,function(e,i){if(i>0){var o=/(max|min)(Width|Height)/.exec(e),r=o[2].charAt(0).toLowerCase()+o[2].slice(1),a=t[r];switch(o[1]){case"min":if(ai)return n=e,!1}}}),n}this.validate=function(e){var r=new qq.Promise;return t("Attempting to validate image."),n(e)?i().then(function(t){var n=o(e,t);n?r.failure(n):r.success()},r.success):r.success(),r}},qq.Session=function(e){"use strict";function t(e){return!!qq.isArray(e)||void i.log("Session response is not an array.","error")}function n(e,n,o,r){var a=!1;n=n&&t(e),n&&qq.each(e,function(e,t){if(null==t.uuid)a=!0,i.log(qq.format("Session response item {} did not include a valid UUID - ignoring.",e),"error");else if(null==t.name)a=!0,i.log(qq.format("Session response item {} did not include a valid name - ignoring.",e),"error");else try{return i.addFileRecord(t),!0}catch(e){a=!0,i.log(e.message,"error")}return!1}),r[n&&!a?"success":"failure"](e,o)}var i={endpoint:null,params:{},customHeaders:{},cors:{},addFileRecord:function(e){},log:function(e,t){}};qq.extend(i,e,!0),this.refresh=function(){var e=new qq.Promise,t=function(t,i,o){n(t,i,o,e)},o=qq.extend({},i),r=new qq.SessionAjaxRequester(qq.extend(o,{onComplete:t}));return r.queryServer(),e}},qq.SessionAjaxRequester=function(e){"use strict";function t(e,t,n){var o=null;if(null!=t.responseText)try{o=qq.parseJson(t.responseText)}catch(e){i.log("Problem parsing session response: "+e.message,"error"),n=!0}i.onComplete(o,!n,t)}var n,i={endpoint:null,customHeaders:{},params:{},cors:{expected:!1,sendCredentials:!1},onComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",endpointStore:{get:function(){return i.endpoint}},customHeaders:i.customHeaders,log:i.log,onComplete:t,cors:i.cors})),qq.extend(this,{queryServer:function(){var e=qq.extend({},i.params);i.log("Session query request."),n.initTransport("sessionRefresh").withParams(e).withCacheBuster().send()}})},qq.Scaler=function(e,t){"use strict";var n=e.customResizer,i=e.sendOriginal,o=e.orient,r=e.defaultType,a=e.defaultQuality/100,s=e.failureText,l=e.includeExif,u=this._getSortedSizes(e.sizes);qq.extend(this,{enabled:qq.supportedFeatures.scaling&&u.length>0,getFileRecords:function(e,c,d){var p=this,q=[],h=d.blob?d.blob:d,f=new qq.Identify(h,t);return f.isPreviewableSync()?(qq.each(u,function(e,i){var u=p._determineOutputType({defaultType:r,requestedType:i.type,refType:h.type});q.push({uuid:qq.getUniqueId(),name:p._getName(c,{name:i.name,type:u,refType:h.type}),blob:new qq.BlobProxy(h,qq.bind(p._generateScaledImage,p,{customResizeFunction:n,maxSize:i.maxSize,orient:o,type:u,quality:a,failedText:s,includeExif:l,log:t}))})}),q.push({uuid:e,name:c,size:h.size,blob:i?h:null})):q.push({uuid:e,name:c,size:h.size,blob:h}),q},handleNewFile:function(e,t,n,i,o,r,a,s){var l=this,u=(e.qqButtonId||e.blob&&e.blob.qqButtonId,[]),c=null,d=s.addFileToHandler,p=s.uploadData,q=s.paramsStore,h=qq.getUniqueId();qq.each(l.getFileRecords(n,t,e),function(e,t){var n,i=t.size;t.blob instanceof qq.BlobProxy&&(i=-1),n=p.addFile({uuid:t.uuid,name:t.name,size:i,batchId:r,proxyGroupId:h}),t.blob instanceof qq.BlobProxy?u.push(n):c=n,t.blob?(d(n,t.blob),o.push({id:n,file:t.blob})):p.setStatus(n,qq.status.REJECTED)}),null!==c&&(qq.each(u,function(e,t){var n={qqparentuuid:p.retrieve({id:c}).uuid,qqparentsize:p.retrieve({id:c}).size};n[a]=p.retrieve({id:t}).uuid,p.setParentId(t,c),q.addReadOnly(t,n)}),u.length&&!function(){var e={};e[a]=p.retrieve({id:c}).uuid,q.addReadOnly(c,e)}())}})},qq.extend(qq.Scaler.prototype,{scaleImage:function(e,t,n){"use strict";if(!qq.supportedFeatures.scaling)throw new qq.Error("Scaling is not supported in this browser!");var i=new qq.Promise,o=n.log,r=n.getFile(e),a=n.uploadData.retrieve({id:e}),s=a&&a.name,l=a&&a.uuid,u={customResizer:t.customResizer,sendOriginal:!1,orient:t.orient,defaultType:t.type||null,defaultQuality:t.quality,failedToScaleText:"Unable to scale",sizes:[{name:"",maxSize:t.maxSize}]},c=new qq.Scaler(u,o);return qq.Scaler&&qq.supportedFeatures.imagePreviews&&r?qq.bind(function(){var t=c.getFileRecords(l,s,r)[0];t&&t.blob instanceof qq.BlobProxy?t.blob.create().then(i.success,i.failure):(o(e+" is not a scalable image!","error"),i.failure())},this)():(i.failure(),o("Could not generate requested scaled image for "+e+". Scaling is either not possible in this browser, or the file could not be located.","error")),i},_determineOutputType:function(e){"use strict";var t=e.requestedType,n=e.defaultType,i=e.refType;return n||t?t&&qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES),t)>=0?"image/tiff"===t?qq.supportedFeatures.tiffPreviews?t:n:t:n:"image/jpeg"!==i?"image/png":i},_getName:function(e,t){"use strict";var n=e.lastIndexOf("."),i=t.type||"image/png",o=t.refType,r="",a=qq.getExtension(e),s="";return t.name&&t.name.trim().length&&(s=" ("+t.name+")"),n>=0?(r=e.substr(0,n),o!==i&&(a=i.split("/")[1]),r+=s+"."+a):r=e+s,r},_getSortedSizes:function(e){"use strict";return e=qq.extend([],e),e.sort(function(e,t){return e.maxSize>t.maxSize?1:e.maxSize=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),n=e.split(",")[0].split(":")[1].split(";")[0],i=new ArrayBuffer(t.length),o=new Uint8Array(i),qq.each(t,function(e,t){o[e]=t.charCodeAt(0)}),this._createBlob(i,n)},_createBlob:function(e,t){"use strict";var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;
+return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})}}),qq.ExifRestorer=function(){var e={};return e.KEY_STR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e.encode64=function(e){var t,n,i,o,r,a="",s="",l="",u=0;do t=e[u++],n=e[u++],s=e[u++],i=t>>2,o=(3&t)<<4|n>>4,r=(15&n)<<2|s>>6,l=63&s,isNaN(n)?r=l=64:isNaN(s)&&(l=64),a=a+this.KEY_STR.charAt(i)+this.KEY_STR.charAt(o)+this.KEY_STR.charAt(r)+this.KEY_STR.charAt(l),t=n=s="",i=o=r=l="";while(ue.length)break}return n},e.decode64=function(e){var t,n,i,o,r,a="",s="",l=0,u=[],c=/[^A-Za-z0-9\+\/\=]/g;if(c.exec(e))throw new Error("There were invalid base64 characters in the input text. Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");do i=this.KEY_STR.indexOf(e.charAt(l++)),o=this.KEY_STR.indexOf(e.charAt(l++)),r=this.KEY_STR.indexOf(e.charAt(l++)),s=this.KEY_STR.indexOf(e.charAt(l++)),t=i<<2|o>>4,n=(15&o)<<4|r>>2,a=(3&r)<<6|s,u.push(t),64!=r&&u.push(n),64!=s&&u.push(a),t=n=a="",i=o=r=s="";while(l=0)return n=!1,!1}),n},u=function(e){p(e,-1,-1),delete n[e]},c=function(e,t,n){(0===t.length||l(t,n))&&(s(o,o),this.reset())},d=function(e){var i=t(e);i>0&&(p(e,0,i),n[e]={loaded:0,total:i})},p=function(e,t,r){var a=n[e]?n[e].loaded:0,l=n[e]?n[e].total:0;t===-1&&r===-1?(i-=a,o-=l):(t&&(i+=t-a),r&&(o+=r-l)),s(i,o)};qq.extend(this,{onAllComplete:c,onStatusChange:function(e,t,n){n===qq.status.CANCELED||n===qq.status.REJECTED?u(e):n===qq.status.SUBMITTING&&d(e)},onIndividualProgress:function(e,t,i){p(e,t,i),n[e]={loaded:t,total:i}},onNewSize:function(e){d(e)},reset:function(){n={},i=0,o=0}})},qq.PasteSupport=function(e){"use strict";function t(e){return e.type&&0===e.type.indexOf("image/")}function n(){r=qq(o.targetElement).attach("paste",function(e){var n=e.clipboardData;n&&qq.each(n.items,function(e,n){if(t(n)){var i=n.getAsFile();o.callbacks.pasteReceived(i)}})})}function i(){r&&r()}var o,r;o={targetElement:null,callbacks:{log:function(e,t){},pasteReceived:function(e){}}},qq.extend(o,e),n(),qq.extend(this,{reset:function(){i()}})},qq.FormSupport=function(e,t,n){"use strict";function i(e){e.getAttribute("action")&&(s.newEndpoint=e.getAttribute("action"))}function o(e,t){return!(e.checkValidity&&!e.checkValidity())||(n("Form did not pass validation checks - will not upload.","error"),void t())}function r(e){var n=e.submit;qq(e).attach("submit",function(i){i=i||window.event,i.preventDefault?i.preventDefault():i.returnValue=!1,o(e,n)&&t()}),e.submit=function(){o(e,n)&&t()}}function a(e){return e&&(qq.isString(e)&&(e=document.getElementById(e)),e&&(n("Attaching to form element."),i(e),l&&r(e))),e}var s=this,l=e.interceptSubmit,u=e.element,c=e.autoUpload;qq.extend(this,{newEndpoint:null,newAutoUpload:c,attachedToForm:!1,getFormInputsAsObject:function(){return null==u?null:s._form2Obj(u)}}),u=a(u),this.attachedToForm=!!u},qq.extend(qq.FormSupport.prototype,{_form2Obj:function(e){"use strict";var t={},n=function(e){var t=["button","image","reset","submit"];return qq.indexOf(t,e.toLowerCase())<0},i=function(e){return qq.indexOf(["checkbox","radio"],e.toLowerCase())>=0},o=function(e){return!(!i(e.type)||e.checked)||e.disabled&&"hidden"!==e.type.toLowerCase()},r=function(e){var t=null;return qq.each(qq(e).children(),function(e,n){if("option"===n.tagName.toLowerCase()&&n.selected)return t=n.value,!1}),t};return qq.each(e.elements,function(e,i){if(!qq.isInput(i,!0)&&"textarea"!==i.tagName.toLowerCase()||!n(i.type)||o(i)){if("select"===i.tagName.toLowerCase()&&!o(i)){var a=r(i);null!==a&&(t[i.name]=a)}}else t[i.name]=i.value}),t}}),qq.azure=qq.azure||{},qq.azure.util=qq.azure.util||function(){"use strict";return{AZURE_PARAM_PREFIX:"x-ms-meta-",_paramNameMatchesAzureParameter:function(e){switch(e){case"Cache-Control":case"Content-Disposition":case"Content-Encoding":case"Content-MD5":case"x-ms-blob-content-encoding":case"x-ms-blob-content-disposition":case"x-ms-blob-content-md5":case"x-ms-blob-cache-control":return!0;default:return!1}},_getPrefixedParamName:function(e){return qq.azure.util._paramNameMatchesAzureParameter(e)?e:qq.azure.util.AZURE_PARAM_PREFIX+e},getParamsAsHeaders:function(e){var t={};return qq.each(e,function(e,n){var i=qq.azure.util._getPrefixedParamName(e),o=null;qq.isFunction(n)?o=String(n()):qq.isObject(n)?qq.extend(t,qq.azure.util.getParamsAsHeaders(n)):o=String(n),null!==o&&(qq.azure.util._paramNameMatchesAzureParameter(e)?t[i]=o:t[i]=encodeURIComponent(o))}),t},parseAzureError:function(e,t){var n,i,o=new DOMParser,r=o.parseFromString(e,"application/xml"),a=r.getElementsByTagName("Error")[0],s={};if(t("Received error response: "+e,"error"),a)return i=a.getElementsByTagName("Message")[0],i&&(s.message=i.textContent),n=a.getElementsByTagName("Code")[0],n&&(s.code=n.textContent),t("Parsed Azure error: "+JSON.stringify(s),"error"),s}}}(),function(){"use strict";qq.nonTraditionalBasePublicApi={setUploadSuccessParams:function(e,t){this._uploadSuccessParamsStore.set(e,t)},setUploadSuccessEndpoint:function(e,t){this._uploadSuccessEndpointStore.set(e,t)}},qq.nonTraditionalBasePrivateApi={_onComplete:function(e,t,n,i){var o,r,a=!!n.success,s=this,l=arguments,u=this._uploadSuccessEndpointStore.get(e),c=this._options.uploadSuccess.customHeaders,d=this._options.uploadSuccess.method,p=this._options.cors,q=new qq.Promise,h=this._uploadSuccessParamsStore.get(e),f=this._paramsStore.get(e),m=function(t){delete s._failedSuccessRequestCallbacks[e],qq.extend(n,t),qq.FineUploaderBasic.prototype._onComplete.apply(s,l),q.success(t)},g=function(r){var a=o;qq.extend(n,r),n&&n.reset&&(a=null),a?s._failedSuccessRequestCallbacks[e]=a:delete s._failedSuccessRequestCallbacks[e],s._onAutoRetry(e,t,n,i,a)||(qq.FineUploaderBasic.prototype._onComplete.apply(s,l),q.failure(r))};return a&&u?(r=new qq.UploadSuccessAjaxRequester({endpoint:u,method:d,customHeaders:c,cors:p,log:qq.bind(this.log,this)}),qq.extend(h,s._getEndpointSpecificParams(e,n,i),!0),f&&qq.extend(h,f,!0),o=qq.bind(function(){r.sendSuccessRequest(e,h).then(m,g)},s),o(),q):qq.FineUploaderBasic.prototype._onComplete.apply(this,arguments)},_manualRetry:function(e){var t=this._failedSuccessRequestCallbacks[e];return qq.FineUploaderBasic.prototype._manualRetry.call(this,e,t)}}}(),function(){"use strict";qq.azure.FineUploaderBasic=function(e){if(!qq.supportedFeatures.ajaxUploading)throw new qq.Error("Uploading directly to Azure is not possible in this browser.");var t={signature:{endpoint:null,customHeaders:{}},blobProperties:{name:"uuid"},uploadSuccess:{endpoint:null,method:"POST",params:{},customHeaders:{}},chunking:{partSize:4e6,minFileSize:4000001}};qq.extend(t,e,!0),qq.FineUploaderBasic.call(this,t),this._uploadSuccessParamsStore=this._createStore(this._options.uploadSuccess.params),this._uploadSuccessEndpointStore=this._createStore(this._options.uploadSuccess.endpoint),this._failedSuccessRequestCallbacks={},this._cannedBlobNames={}},qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.basePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePublicApi),qq.extend(qq.azure.FineUploaderBasic.prototype,qq.nonTraditionalBasePrivateApi),qq.extend(qq.azure.FineUploaderBasic.prototype,{getBlobName:function(e){return null==this._cannedBlobNames[e]?this._handler.getThirdPartyFileId(e):this._cannedBlobNames[e]},_getEndpointSpecificParams:function(e){return{blob:this.getBlobName(e),uuid:this.getUuid(e),name:this.getName(e),container:this._endpointStore.get(e)}},_createUploadHandler:function(){return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,{signature:this._options.signature,onGetBlobName:qq.bind(this._determineBlobName,this),deleteBlob:qq.bind(this._deleteBlob,this,!0)},"azure")},_determineBlobName:function(e){var t=this._options.blobProperties.name,n=this.getUuid(e),i=this.getName(e),o=qq.getExtension(i),r=n;if(!qq.isString(t))return t.call(this,e);switch(t){case"uuid":return void 0!==o&&(r+="."+o),(new qq.Promise).success(r);case"filename":return(new qq.Promise).success(i);default:return new qq.Promise.failure("Invalid blobName option value - "+t)}},_addCannedFile:function(e){var t;if(null==e.blobName)throw new qq.Error("Did not find blob name property in server session response. This is required!");return t=qq.FineUploaderBasic.prototype._addCannedFile.apply(this,arguments),this._cannedBlobNames[t]=e.blobName,t},_deleteBlob:function(e,t){var n=this,i={},o={get:function(e){return n._endpointStore.get(e)+"/"+n.getBlobName(e)}},r={get:function(e){return i[e]}},a=function(e,t){i[e]=t,l.send(e)},s=function(t,i,o){e?(n.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS","error"),qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t))):(n._onDeleteComplete(t,o,!0),n._options.callbacks.onDeleteComplete(t,o,!0))},l=new qq.azure.DeleteBlob({endpointStore:r,log:qq.bind(n.log,n),onDelete:function(e){n._onDelete(e),n._options.callbacks.onDelete(e)},onDeleteComplete:function(t,o,r){delete i[t],r&&(e?n.log("Will cancel upload, but failed to remove uncommitted parts from Azure.","error"):qq.azure.util.parseAzureError(o.responseText,qq.bind(n.log,n))),e?(qq.FineUploaderBasic.prototype._onCancel.call(n,t,n.getName(t)),n.log("Deleted uncommitted blob chunks for "+t)):(n._onDeleteComplete(t,o,r),n._options.callbacks.onDeleteComplete(t,o,r))}}),u=new qq.azure.GetSas({cors:this._options.cors,customHeaders:this._options.signature.customHeaders,endpointStore:{get:function(){return n._options.signature.endpoint}},restRequestVerb:l.method,log:qq.bind(n.log,n)});u.request(t,o.get(t)).then(qq.bind(a,n,t),qq.bind(s,n,t))},_createDeleteHandler:function(){var e=this;return{sendDelete:function(t,n){e._deleteBlob(!1,t)}}}})}(),qq.azure.XhrUploadHandler=function(e,t){"use strict";function n(e){var t=new qq.Promise;return o(e).then(function(n){var i=a._getMimeType(e),o=a._getPersistableData(e).blockIdEntries;b.putBlockList.send(e,n,o,i,function(t){a._registerXhr(e,null,t,b.putBlockList)}).then(function(n){s("Success combining chunks for id "+e),t.success({},n)},function(n){s("Attempt to combine chunks failed for id "+e,"error"),r(n,t)})},t.failure),t}function i(e){var t=u.get(e),n=new qq.Promise,i=function(i){a._setThirdPartyFileId(e,i),n.success(t+"/"+i)},o=function(e){n.failure(e)};return f(e).then(i,o),n}function o(e,t){var n=null==t?e:e+"."+t,o=new qq.Promise,r=function(e){s("GET SAS request succeeded."),o.success(e)},a=function(e,t){s("GET SAS request failed: "+e,"error"),o.failure({error:"Problem communicating with local server"},t)},l=function(e){b.getSasForPutBlobOrBlock.request(n,e).then(r,a)},u=function(t){s(qq.format("Failed to determine blob name for ID {} - {}",e,t),"error"),o.failure({error:t})};return i(e).then(l,u),o}function r(e,t){var n=qq.azure.util.parseAzureError(e.responseText,s),i="Problem sending file to Azure";t.failure({error:i,azureError:n&&n.message,reset:403===e.status})}var a=this,s=t.log,l=e.cors,u=e.endpointStore,c=e.paramsStore,d=e.signature,p=e.filenameParam,q=e.chunking.minFileSize,h=e.deleteBlob,f=e.onGetBlobName,m=t.getName,g=t.getSize,_=function(e){var t=c.get(e);return t[p]=m(e),t},b={putBlob:new qq.azure.PutBlob({getBlobMetadata:_,log:s}),putBlock:new qq.azure.PutBlock({log:s}),putBlockList:new qq.azure.PutBlockList({getBlobMetadata:_,log:s}),getSasForPutBlobOrBlock:new qq.azure.GetSas({cors:l,customHeaders:d.customHeaders,endpointStore:{get:function(){return d.endpoint}},log:s,restRequestVerb:"PUT"})};qq.extend(this,{uploadChunk:function(e,t){var n=new qq.Promise;return o(e,t).then(function(i){var o=a._createXhr(e,t),l=a._getChunkData(e,t);a._registerProgressHandler(e,t,l.size),a._registerXhr(e,t,o,b.putBlock),b.putBlock.upload(e+"."+t,o,i,t,l.blob).then(function(t){a._getPersistableData(e).blockIdEntries||(a._getPersistableData(e).blockIdEntries=[]),a._getPersistableData(e).blockIdEntries.push(t),s("Put Block call succeeded for "+e),n.success({},o)},function(){s(qq.format("Put Block call failed for ID {} on part {}",e,t),"error"),r(o,n)})},n.failure),n},uploadFile:function(e){var t=new qq.Promise,n=a.getFile(e);return o(e).then(function(i){var o=a._createXhr(e);a._registerProgressHandler(e),b.putBlob.upload(e,o,i,n).then(function(){s("Put Blob call succeeded for "+e),t.success({},o)},function(){s("Put Blob call failed for "+e,"error"),r(o,t)})},t.failure),t}}),qq.extend(this,new qq.XhrUploadHandler({options:qq.extend({namespace:"azure"},e),proxy:qq.extend({getEndpoint:e.endpointStore.get},t)})),qq.override(this,function(e){return{expunge:function(t){var n=a._wasCanceled(t),i=a._getPersistableData(t),o=i&&i.blockIdEntries||[];n&&o.length>0&&h(t),e.expunge(t)},finalizeChunks:function(e){return n(e)},_shouldChunkThisFile:function(t){var n=e._shouldChunkThisFile(t);return n&&g(t)>=q}}})},qq.azure.GetSas=function(e){"use strict";function t(e,t,n){var i=o[e];n?i.failure("Received response code "+t.status,t):t.responseText.length?i.success(t.responseText):i.failure("Empty response.",t),delete o[e]}var n,i={cors:{expected:!1,sendCredentials:!1},customHeaders:{},restRequestVerb:"PUT",endpointStore:null,log:function(e,t){}},o={};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",successfulResponseCodes:{GET:[200]},contentType:null,customHeaders:i.customHeaders,endpointStore:i.endpointStore,cors:i.cors,log:i.log,onComplete:t})),qq.extend(this,{request:function(e,t){var r=new qq.Promise,a=i.restRequestVerb;return i.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.",a,e)),o[e]=r,n.initTransport(e).withParams({bloburi:t,_method:a}).withCacheBuster().send(),r}})},qq.UploadSuccessAjaxRequester=function(e){"use strict";function t(e,t,n){var r,a=i[e],s=t.responseText,l={success:!0},u={success:!1};delete i[e],o.log(qq.format("Received the following response body to an upload success request for id {}: {}",e,s));try{r=qq.parseJson(s),n||r&&(r.error||r.success===!1)?(o.log("Upload success request was rejected by the server.","error"),a.failure(qq.extend(r,u))):(o.log("Upload success was acknowledged by the server."),a.success(qq.extend(r,l)))}catch(t){n?(o.log(qq.format("Your server indicated failure in its upload success request response for id {}!",e),"error"),a.failure(u)):(o.log("Upload success was acknowledged by the server."),a.success(l))}}var n,i=[],o={method:"POST",endpoint:null,maxConnections:3,customHeaders:{},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){}};qq.extend(o,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",method:o.method,endpointStore:{get:function(){return o.endpoint}},paramsStore:o.paramsStore,maxConnections:o.maxConnections,customHeaders:o.customHeaders,log:o.log,onComplete:t,cors:o.cors})),qq.extend(this,{sendSuccessRequest:function(e,t){var r=new qq.Promise;return o.log("Submitting upload success request/notification for "+e),n.initTransport(e).withParams(t).send(),i[e]=r,r}})},qq.azure.DeleteBlob=function(e){"use strict";var t,n="DELETE",i={endpointStore:{},onDelete:function(e){},onDeleteComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[202],e}(),contentType:null,endpointStore:i.endpointStore,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete})),qq.extend(this,{method:n,send:function(e){return i.log("Submitting Delete Blob request for "+e),t.initTransport(e).send()}})},qq.azure.PutBlob=function(e){"use strict";var t,n="PUT",i={getBlobMetadata:function(e){},log:function(e,t){}},o={},r={},a={get:function(e){return o[e]}};qq.extend(i,e),t=qq.extend(this,new qq.AjaxRequester({validMethods:[n],method:n,successfulResponseCodes:function(){var e={};return e[n]=[201],e}(),contentType:null,customHeaders:function(e){var t=i.getBlobMetadata(e),n=qq.azure.util.getParamsAsHeaders(t);return n["x-ms-blob-type"]="BlockBlob",n},endpointStore:a,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:i.log,onComplete:function(e,t,n){var i=r[e];delete o[e],delete r[e],n?i.failure():i.success()}})),qq.extend(this,{method:n,upload:function(e,n,a,s){var l=new qq.Promise;return i.log("Submitting Put Blob request for "+e),r[e]=l,o[e]=a,t.initTransport(e).withPayload(s).withHeaders({"Content-Type":s.type}).send(n),l}})},qq.azure.PutBlock=function(e){"use strict";function t(e){var t=5,n=new Array(t+1).join("0"),i=(n+e).slice(-t);return btoa(i)}var n,i="PUT",o={},r={},a={log:function(e,t){}},s={},l={get:function(e){return s[e]}};qq.extend(a,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),contentType:null,endpointStore:l,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:a.log,onComplete:function(e,t,n){var i=r[e],a=o[e];delete s[e],delete r[e],delete o[e],n?i.failure():i.success(a)}})),qq.extend(this,{method:i,upload:function(e,i,l,u,c){var d=new qq.Promise,p=t(u);return r[e]=d,a.log(qq.format("Submitting Put Block request for {} = part {}",e,u)),s[e]=qq.format("{}&comp=block&blockid={}",l,encodeURIComponent(p)),o[e]={part:u,id:p},n.initTransport(e).withPayload(c).send(i),d}})},qq.azure.PutBlockList=function(e){"use strict";function t(e){var t=document.implementation.createDocument(null,"BlockList",null);return e.sort(function(e,t){return e.part-t.part}),qq.each(e,function(e,n){var i=t.createElement("Latest"),o=t.createTextNode(n.id);i.appendChild(o),qq(t).children()[0].appendChild(i)}),(new XMLSerializer).serializeToString(t)}var n,i="PUT",o={},r={getBlobMetadata:function(e){},log:function(e,t){}},a={},s={get:function(e){return a[e]}};qq.extend(r,e),n=qq.extend(this,new qq.AjaxRequester({validMethods:[i],method:i,successfulResponseCodes:function(){var e={};return e[i]=[201],e}(),customHeaders:function(e){var t=r.getBlobMetadata(e);return qq.azure.util.getParamsAsHeaders(t)},contentType:"text/plain",endpointStore:s,allowXRequestedWithAndCacheControl:!1,cors:{expected:!0},log:r.log,onSend:function(){},onComplete:function(e,t,n){var i=o[e];delete a[e],delete o[e],n?i.failure(t):i.success(t)}})),qq.extend(this,{method:i,send:function(e,i,s,l,u){var c,d=new qq.Promise,p=t(s);return o[e]=d,r.log(qq.format("Submitting Put Block List request for {}",e)),a[e]=qq.format("{}&comp=blocklist",i),c=n.initTransport(e).withPayload(p).withHeaders({"x-ms-blob-content-type":l}).send(),u(c),d}})},qq.DragAndDrop=function(e){"use strict";function t(e,t){var n=Array.prototype.slice.call(e);u.callbacks.dropLog("Grabbed "+e.length+" dropped files."),t.dropDisabled(!1),u.callbacks.processingDroppedFilesComplete(n,t.getElement())}function n(e){var t=new qq.Promise;return e.isFile?e.file(function(n){var i=e.name,o=e.fullPath,r=o.indexOf(i);o=o.substr(0,r),"/"===o.charAt(0)&&(o=o.substr(1)),n.qqPath=o,q.push(n),t.success()},function(n){u.callbacks.dropLog("Problem parsing '"+e.fullPath+"'. FileError code "+n.code+".","error"),t.failure()}):e.isDirectory&&i(e).then(function(e){var i=e.length;qq.each(e,function(e,o){n(o).done(function(){i-=1,0===i&&t.success()})}),e.length||t.success()},function(n){u.callbacks.dropLog("Problem parsing '"+e.fullPath+"'. FileError code "+n.code+".","error"),t.failure()}),t}function i(e,t,n,o){var r=o||new qq.Promise,a=t||e.createReader();return a.readEntries(function(t){var o=n?n.concat(t):t;t.length?setTimeout(function(){i(e,a,o,r)},0):r.success(o)},r.failure),r}function o(e,t){var i=[],o=new qq.Promise;return u.callbacks.processingDroppedFiles(),t.dropDisabled(!0),e.files.length>1&&!u.allowMultipleItems?(u.callbacks.processingDroppedFilesComplete([]),u.callbacks.dropError("tooManyFilesError",""),t.dropDisabled(!1),o.failure()):(q=[],qq.isFolderDropSupported(e)?qq.each(e.items,function(e,t){var r=t.webkitGetAsEntry();r&&(r.isFile?q.push(t.getAsFile()):i.push(n(r).done(function(){i.pop(),0===i.length&&o.success()})))}):q=e.files,0===i.length&&o.success()),o}function r(e){var n=new qq.UploadDropZone({HIDE_ZONES_EVENT_NAME:c,element:e,onEnter:function(t){qq(e).addClass(u.classes.dropActive),t.stopPropagation()},onLeaveNotDescendants:function(t){qq(e).removeClass(u.classes.dropActive)},onDrop:function(e){o(e.dataTransfer,n).then(function(){t(q,n)},function(){u.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.","error")})}});return h.addDisposer(function(){n.dispose()}),qq(e).hasAttribute(d)&&qq(e).hide(),p.push(n),n}function a(e){var t;return qq.each(e.dataTransfer.types,function(e,n){if("Files"===n)return t=!0,!1}),t}function s(e){return qq.firefox()?!e.relatedTarget:qq.safari()?e.x<0||e.y<0:0===e.x&&0===e.y}function l(){var e=u.dropZoneElements,t=function(){setTimeout(function(){qq.each(e,function(e,t){qq(t).hasAttribute(d)&&qq(t).hide(),qq(t).removeClass(u.classes.dropActive)})},10)};qq.each(e,function(t,n){var i=r(n);e.length&&qq.supportedFeatures.fileDrop&&h.attach(document,"dragenter",function(t){!i.dropDisabled()&&a(t)&&qq.each(e,function(e,t){t instanceof HTMLElement&&qq(t).hasAttribute(d)&&qq(t).css({display:"block"})})})}),h.attach(document,"dragleave",function(e){s(e)&&t()}),h.attach(qq(document).children()[0],"mouseenter",function(e){t()}),h.attach(document,"drop",function(e){e.preventDefault(),t()}),h.attach(document,c,t)}var u,c="qq-hidezones",d="qq-hide-dropzone",p=[],q=[],h=new qq.DisposeSupport;u={dropZoneElements:[],allowMultipleItems:!0,classes:{dropActive:null},callbacks:new qq.DragAndDrop.callbacks},qq.extend(u,e,!0),l(),qq.extend(this,{setupExtraDropzone:function(e){u.dropZoneElements.push(e),r(e)},removeDropzone:function(e){var t,n=u.dropZoneElements;for(t in n)if(n[t]===e)return n.splice(t,1)},dispose:function(){h.dispose(),qq.each(p,function(e,t){t.dispose()})}})},qq.DragAndDrop.callbacks=function(){"use strict";return{processingDroppedFiles:function(){},processingDroppedFilesComplete:function(e,t){},dropError:function(e,t){qq.log("Drag & drop error code '"+e+" with these specifics: '"+t+"'","error")},dropLog:function(e,t){qq.log(e,t)}}},qq.UploadDropZone=function(e){"use strict";function t(){return qq.safari()||qq.firefox()&&qq.windows()}function n(e){c||(t?d.attach(document,"dragover",function(e){e.preventDefault()}):d.attach(document,"dragover",function(e){e.dataTransfer&&(e.dataTransfer.dropEffect="none",e.preventDefault())}),c=!0)}function i(e){if(!qq.supportedFeatures.fileDrop)return!1;var t,n=e.dataTransfer,i=qq.safari();return t=!(!qq.ie()||!qq.supportedFeatures.fileDrop)||"none"!==n.effectAllowed,n&&t&&(n.files||!i&&n.types.contains&&n.types.contains("Files"))}function o(e){return void 0!==e&&(u=e),u}function r(){function e(){t=document.createEvent("Event"),t.initEvent(s.HIDE_ZONES_EVENT_NAME,!0,!0)}var t;if(window.CustomEvent)try{t=new CustomEvent(s.HIDE_ZONES_EVENT_NAME)}catch(t){e()}else e();document.dispatchEvent(t)}function a(){d.attach(l,"dragover",function(e){if(i(e)){var t=qq.ie()&&qq.supportedFeatures.fileDrop?null:e.dataTransfer.effectAllowed;"move"===t||"linkMove"===t?e.dataTransfer.dropEffect="move":e.dataTransfer.dropEffect="copy",e.stopPropagation(),e.preventDefault()}}),d.attach(l,"dragenter",function(e){if(!o()){if(!i(e))return;s.onEnter(e)}}),d.attach(l,"dragleave",function(e){if(i(e)){s.onLeave(e);var t=document.elementFromPoint(e.clientX,e.clientY);qq(this).contains(t)||s.onLeaveNotDescendants(e)}}),d.attach(l,"drop",function(e){if(!o()){if(!i(e))return;e.preventDefault(),e.stopPropagation(),s.onDrop(e),r()}})}var s,l,u,c,d=new qq.DisposeSupport;s={element:null,onEnter:function(e){},onLeave:function(e){},onLeaveNotDescendants:function(e){},onDrop:function(e){}},qq.extend(s,e),l=s.element,n(),a(),qq.extend(this,{dropDisabled:function(e){return o(e)},dispose:function(){d.dispose()},getElement:function(){return l}})},function(){"use strict";qq.uiPublicApi={addInitialFiles:function(e){this._parent.prototype.addInitialFiles.apply(this,arguments),this._templating.addCacheToDom()},clearStoredFiles:function(){this._parent.prototype.clearStoredFiles.apply(this,arguments),this._templating.clearFiles()},addExtraDropzone:function(e){this._dnd&&this._dnd.setupExtraDropzone(e)},removeExtraDropzone:function(e){if(this._dnd)return this._dnd.removeDropzone(e)},getItemByFileId:function(e){if(!this._templating.isHiddenForever(e))return this._templating.getFileContainer(e)},reset:function(){this._parent.prototype.reset.apply(this,arguments),this._templating.reset(),!this._options.button&&this._templating.getButton()&&(this._defaultButtonId=this._createUploadButton({element:this._templating.getButton(),title:this._options.text.fileInputTitle}).getButtonId()),this._dnd&&(this._dnd.dispose(),this._dnd=this._setupDragAndDrop()),this._totalFilesInBatch=0,this._filesInBatchAddedToUi=0,this._setupClickAndEditEventHandlers()},setName:function(e,t){var n=this._options.formatFileName(t);this._parent.prototype.setName.apply(this,arguments),this._templating.updateFilename(e,n)},pauseUpload:function(e){var t=this._parent.prototype.pauseUpload.apply(this,arguments);return t&&this._templating.uploadPaused(e),t},continueUpload:function(e){var t=this._parent.prototype.continueUpload.apply(this,arguments);return t&&this._templating.uploadContinued(e),t},getId:function(e){return this._templating.getFileId(e)},getDropTarget:function(e){var t=this.getFile(e);return t.qqDropTarget}},qq.uiPrivateApi={_getButton:function(e){var t=this._parent.prototype._getButton.apply(this,arguments);return t||e===this._defaultButtonId&&(t=this._templating.getButton()),t},_removeFileItem:function(e){this._templating.removeFile(e)},_setupClickAndEditEventHandlers:function(){this._fileButtonsClickHandler=qq.FileButtonsClickHandler&&this._bindFileButtonsClickEvent(),this._focusinEventSupported=!qq.firefox(),this._isEditFilenameEnabled()&&(this._filenameClickHandler=this._bindFilenameClickEvent(),this._filenameInputFocusInHandler=this._bindFilenameInputFocusInEvent(),this._filenameInputFocusHandler=this._bindFilenameInputFocusEvent())},_setupDragAndDrop:function(){var e=this,t=this._options.dragAndDrop.extraDropzones,n=this._templating,i=n.getDropZone();return i&&t.push(i),new qq.DragAndDrop({dropZoneElements:t,allowMultipleItems:this._options.multiple,classes:{dropActive:this._options.classes.dropActive},callbacks:{processingDroppedFiles:function(){n.showDropProcessing()},processingDroppedFilesComplete:function(t,i){n.hideDropProcessing(),qq.each(t,function(e,t){t.qqDropTarget=i}),t.length&&e.addFiles(t,null,null)},dropError:function(t,n){e._itemError(t,n)},dropLog:function(t,n){e.log(t,n)}}})},_bindFileButtonsClickEvent:function(){var e=this;return new qq.FileButtonsClickHandler({templating:this._templating,log:function(t,n){e.log(t,n)},onDeleteFile:function(t){e.deleteFile(t)},onCancel:function(t){e.cancel(t)},onRetry:function(t){e.retry(t)},onPause:function(t){e.pauseUpload(t)},onContinue:function(t){e.continueUpload(t)},onGetName:function(t){return e.getName(t)}})},_isEditFilenameEnabled:function(){return this._templating.isEditFilenamePossible()&&!this._options.autoUpload&&qq.FilenameClickHandler&&qq.FilenameInputFocusHandler&&qq.FilenameInputFocusHandler},_filenameEditHandler:function(){var e=this,t=this._templating;return{templating:t,log:function(t,n){e.log(t,n)},onGetUploadStatus:function(t){return e.getUploads({id:t}).status},onGetName:function(t){return e.getName(t)},onSetName:function(t,n){e.setName(t,n)},onEditingStatusChange:function(e,n){var i=qq(t.getEditInput(e)),o=qq(t.getFileContainer(e));n?(i.addClass("qq-editing"),t.hideFilename(e),t.hideEditIcon(e)):(i.removeClass("qq-editing"),t.showFilename(e),t.showEditIcon(e)),o.addClass("qq-temp").removeClass("qq-temp")}}},_onUploadStatusChange:function(e,t,n){this._parent.prototype._onUploadStatusChange.apply(this,arguments),this._isEditFilenameEnabled()&&this._templating.getFileContainer(e)&&n!==qq.status.SUBMITTED&&(this._templating.markFilenameEditable(e),this._templating.hideEditIcon(e)),t===qq.status.UPLOAD_RETRYING&&n===qq.status.UPLOADING?(this._templating.hideRetry(e),this._templating.setStatusText(e),qq(this._templating.getFileContainer(e)).removeClass(this._classes.retrying)):n===qq.status.UPLOAD_FAILED&&this._templating.hidePause(e)},_bindFilenameInputFocusInEvent:function(){var e=qq.extend({},this._filenameEditHandler());return new qq.FilenameInputFocusInHandler(e)},_bindFilenameInputFocusEvent:function(){var e=qq.extend({},this._filenameEditHandler());return new qq.FilenameInputFocusHandler(e)},_bindFilenameClickEvent:function(){var e=qq.extend({},this._filenameEditHandler());return new qq.FilenameClickHandler(e)},_storeForLater:function(e){this._parent.prototype._storeForLater.apply(this,arguments),this._templating.hideSpinner(e)},_onAllComplete:function(e,t){this._parent.prototype._onAllComplete.apply(this,arguments),this._templating.resetTotalProgress()},_onSubmit:function(e,t){var n=this.getFile(e);n&&n.qqPath&&this._options.dragAndDrop.reportDirectoryPaths&&this._paramsStore.addReadOnly(e,{qqpath:n.qqPath}),this._parent.prototype._onSubmit.apply(this,arguments),this._addToList(e,t)},_onSubmitted:function(e){this._isEditFilenameEnabled()&&(this._templating.markFilenameEditable(e),this._templating.showEditIcon(e),this._focusinEventSupported||this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(e)))},_onProgress:function(e,t,n,i){this._parent.prototype._onProgress.apply(this,arguments),this._templating.updateProgress(e,n,i),0===i||100===Math.round(n/i*100)?(this._templating.hideCancel(e),this._templating.hidePause(e),this._templating.hideProgress(e),this._templating.setStatusText(e,this._options.text.waitingForResponse),this._displayFileSize(e)):this._displayFileSize(e,n,i)},_onTotalProgress:function(e,t){this._parent.prototype._onTotalProgress.apply(this,arguments),this._templating.updateTotalProgress(e,t)},_onComplete:function(e,t,n,i){function o(t){s&&(a.setStatusText(e),qq(s).removeClass(l._classes.retrying),a.hideProgress(e),l.getUploads({id:e}).status!==qq.status.UPLOAD_FAILED&&a.hideCancel(e),a.hideSpinner(e),t.success?l._markFileAsSuccessful(e):(qq(s).addClass(l._classes.fail),a.showCancel(e),a.isRetryPossible()&&!l._preventRetries[e]&&(qq(s).addClass(l._classes.retryable),a.showRetry(e)),l._controlFailureTextDisplay(e,t)))}var r=this._parent.prototype._onComplete.apply(this,arguments),a=this._templating,s=a.getFileContainer(e),l=this;return r instanceof qq.Promise?r.done(function(e){o(e)}):o(n),r},_markFileAsSuccessful:function(e){var t=this._templating;this._isDeletePossible()&&t.showDeleteButton(e),qq(t.getFileContainer(e)).addClass(this._classes.success),this._maybeUpdateThumbnail(e)},_onUploadPrep:function(e){this._parent.prototype._onUploadPrep.apply(this,arguments),this._templating.showSpinner(e)},_onUpload:function(e,t){var n=this._parent.prototype._onUpload.apply(this,arguments);return this._templating.showSpinner(e),
+n},_onUploadChunk:function(e,t){this._parent.prototype._onUploadChunk.apply(this,arguments),t.partIndex>0&&this._handler.isResumable(e)&&this._templating.allowPause(e)},_onCancel:function(e,t){this._parent.prototype._onCancel.apply(this,arguments),this._removeFileItem(e),0===this._getNotFinished()&&this._templating.resetTotalProgress()},_onBeforeAutoRetry:function(e){var t,n,i;this._parent.prototype._onBeforeAutoRetry.apply(this,arguments),this._showCancelLink(e),this._options.retry.showAutoRetryNote&&(t=this._autoRetries[e],n=this._options.retry.maxAutoAttempts,i=this._options.retry.autoRetryNote.replace(/\{retryNum\}/g,t),i=i.replace(/\{maxAuto\}/g,n),this._templating.setStatusText(e,i),qq(this._templating.getFileContainer(e)).addClass(this._classes.retrying))},_onBeforeManualRetry:function(e){return this._parent.prototype._onBeforeManualRetry.apply(this,arguments)?(this._templating.resetProgress(e),qq(this._templating.getFileContainer(e)).removeClass(this._classes.fail),this._templating.setStatusText(e),this._templating.showSpinner(e),this._showCancelLink(e),!0):(qq(this._templating.getFileContainer(e)).addClass(this._classes.retryable),this._templating.showRetry(e),!1)},_onSubmitDelete:function(e){var t=qq.bind(this._onSubmitDeleteSuccess,this);this._parent.prototype._onSubmitDelete.call(this,e,t)},_onSubmitDeleteSuccess:function(e,t,n){this._options.deleteFile.forceConfirm?this._showDeleteConfirm.apply(this,arguments):this._sendDeleteRequest.apply(this,arguments)},_onDeleteComplete:function(e,t,n){this._parent.prototype._onDeleteComplete.apply(this,arguments),this._templating.hideSpinner(e),n?(this._templating.setStatusText(e,this._options.deleteFile.deletingFailedText),this._templating.showDeleteButton(e)):this._removeFileItem(e)},_sendDeleteRequest:function(e,t,n){this._templating.hideDeleteButton(e),this._templating.showSpinner(e),this._templating.setStatusText(e,this._options.deleteFile.deletingStatusText),this._deleteHandler.sendDelete.apply(this,arguments)},_showDeleteConfirm:function(e,t,n){var i,o=this.getName(e),r=this._options.deleteFile.confirmMessage.replace(/\{filename\}/g,o),a=(this.getUuid(e),arguments),s=this;i=this._options.showConfirm(r),qq.isGenericPromise(i)?i.then(function(){s._sendDeleteRequest.apply(s,a)}):i!==!1&&s._sendDeleteRequest.apply(s,a)},_addToList:function(e,t,n){var i,o,r=0,a=this._handler.isProxied(e)&&this._options.scaling.hideScaled;this._options.display.prependFiles&&(this._totalFilesInBatch>1&&this._filesInBatchAddedToUi>0&&(r=this._filesInBatchAddedToUi-1),i={index:r}),n||(this._options.disableCancelForFormUploads&&!qq.supportedFeatures.ajaxUploading&&this._templating.disableCancel(),this._options.multiple||(o=this.getUploads({id:e}),this._handledProxyGroup=this._handledProxyGroup||o.proxyGroupId,o.proxyGroupId===this._handledProxyGroup&&o.proxyGroupId||(this._handler.cancelAll(),this._clearList(),this._handledProxyGroup=null))),n?(this._templating.addFileToCache(e,this._options.formatFileName(t),i,a),this._templating.updateThumbnail(e,this._thumbnailUrls[e],!0,this._options.thumbnails.customResizer)):(this._templating.addFile(e,this._options.formatFileName(t),i,a),this._templating.generatePreview(e,this.getFile(e),this._options.thumbnails.customResizer)),this._filesInBatchAddedToUi+=1,(n||this._options.display.fileSizeOnSubmit&&qq.supportedFeatures.ajaxUploading)&&this._displayFileSize(e)},_clearList:function(){this._templating.clearFiles(),this.clearStoredFiles()},_displayFileSize:function(e,t,n){var i=this.getSize(e),o=this._formatSize(i);i>=0&&(void 0!==t&&void 0!==n&&(o=this._formatProgress(t,n)),this._templating.updateSize(e,o))},_formatProgress:function(e,t){function n(e,t){i=i.replace(e,t)}var i=this._options.text.formatProgress;return n("{percent}",Math.round(e/t*100)),n("{total_size}",this._formatSize(t)),i},_controlFailureTextDisplay:function(e,t){var n,i,o;n=this._options.failedUploadTextDisplay.mode,i=this._options.failedUploadTextDisplay.responseProperty,"custom"===n?(o=t[i],o||(o=this._options.text.failUpload),this._templating.setStatusText(e,o),this._options.failedUploadTextDisplay.enableTooltip&&this._showTooltip(e,o)):"default"===n?this._templating.setStatusText(e,this._options.text.failUpload):"none"!==n&&this.log("failedUploadTextDisplay.mode value of '"+n+"' is not valid","warn")},_showTooltip:function(e,t){this._templating.getFileContainer(e).title=t},_showCancelLink:function(e){this._options.disableCancelForFormUploads&&!qq.supportedFeatures.ajaxUploading||this._templating.showCancel(e)},_itemError:function(e,t,n){var i=this._parent.prototype._itemError.apply(this,arguments);this._options.showMessage(i)},_batchError:function(e){this._parent.prototype._batchError.apply(this,arguments),this._options.showMessage(e)},_setupPastePrompt:function(){var e=this;this._options.callbacks.onPasteReceived=function(){var t=e._options.paste.namePromptMessage,n=e._options.paste.defaultName;return e._options.showPrompt(t,n)}},_fileOrBlobRejected:function(e,t){this._totalFilesInBatch-=1,this._parent.prototype._fileOrBlobRejected.apply(this,arguments)},_prepareItemsForUpload:function(e,t,n){this._totalFilesInBatch=e.length,this._filesInBatchAddedToUi=0,this._parent.prototype._prepareItemsForUpload.apply(this,arguments)},_maybeUpdateThumbnail:function(e){var t=this._thumbnailUrls[e],n=this.getUploads({id:e}).status;n===qq.status.DELETED||!t&&!this._options.thumbnails.placeholders.waitUntilResponse&&qq.supportedFeatures.imagePreviews||this._templating.updateThumbnail(e,t,this._options.thumbnails.customResizer)},_addCannedFile:function(e){var t=this._parent.prototype._addCannedFile.apply(this,arguments);return this._addToList(t,this.getName(t),!0),this._templating.hideSpinner(t),this._templating.hideCancel(t),this._markFileAsSuccessful(t),t},_setSize:function(e,t){this._parent.prototype._setSize.apply(this,arguments),this._templating.updateSize(e,this._formatSize(t))},_sessionRequestComplete:function(){this._templating.addCacheToDom(),this._parent.prototype._sessionRequestComplete.apply(this,arguments)}}}(),qq.FineUploader=function(e,t){"use strict";var n=this;this._parent=t?qq[t].FineUploaderBasic:qq.FineUploaderBasic,this._parent.apply(this,arguments),qq.extend(this._options,{element:null,button:null,listElement:null,dragAndDrop:{extraDropzones:[],reportDirectoryPaths:!1},text:{formatProgress:"{percent}% of {total_size}",failUpload:"Upload failed",waitingForResponse:"Processing...",paused:"Paused"},template:"qq-template",classes:{retrying:"qq-upload-retrying",retryable:"qq-upload-retryable",success:"qq-upload-success",fail:"qq-upload-fail",editable:"qq-editable",hide:"qq-hide",dropActive:"qq-upload-drop-area-active"},failedUploadTextDisplay:{mode:"default",responseProperty:"error",enableTooltip:!0},messages:{tooManyFilesError:"You may only drop one file",unsupportedBrowser:"Unrecoverable error - this browser does not permit file uploading of any kind."},retry:{showAutoRetryNote:!0,autoRetryNote:"Retrying {retryNum}/{maxAuto}..."},deleteFile:{forceConfirm:!1,confirmMessage:"Are you sure you want to delete {filename}?",deletingStatusText:"Deleting...",deletingFailedText:"Delete failed"},display:{fileSizeOnSubmit:!1,prependFiles:!1},paste:{promptForName:!1,namePromptMessage:"Please name this image"},thumbnails:{customResizer:null,maxCount:0,placeholders:{waitUntilResponse:!1,notAvailablePath:null,waitingPath:null},timeBetweenThumbs:750},scaling:{hideScaled:!1},showMessage:function(e){return n._templating.hasDialog("alert")?n._templating.showDialog("alert",e):void setTimeout(function(){window.alert(e)},0)},showConfirm:function(e){return n._templating.hasDialog("confirm")?n._templating.showDialog("confirm",e):window.confirm(e)},showPrompt:function(e,t){return n._templating.hasDialog("prompt")?n._templating.showDialog("prompt",e,t):window.prompt(e,t)}},!0),qq.extend(this._options,e,!0),this._templating=new qq.Templating({log:qq.bind(this.log,this),templateIdOrEl:this._options.template,containerEl:this._options.element,fileContainerEl:this._options.listElement,button:this._options.button,imageGenerator:this._imageGenerator,classes:{hide:this._options.classes.hide,editable:this._options.classes.editable},limits:{maxThumbs:this._options.thumbnails.maxCount,timeBetweenThumbs:this._options.thumbnails.timeBetweenThumbs},placeholders:{waitUntilUpdate:this._options.thumbnails.placeholders.waitUntilResponse,thumbnailNotAvailable:this._options.thumbnails.placeholders.notAvailablePath,waitingForThumbnail:this._options.thumbnails.placeholders.waitingPath},text:this._options.text}),this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari()?this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari):!qq.supportedFeatures.uploading||this._options.cors.expected&&!qq.supportedFeatures.uploadCors?this._templating.renderFailure(this._options.messages.unsupportedBrowser):(this._wrapCallbacks(),this._templating.render(),this._classes=this._options.classes,!this._options.button&&this._templating.getButton()&&(this._defaultButtonId=this._createUploadButton({element:this._templating.getButton(),title:this._options.text.fileInputTitle}).getButtonId()),this._setupClickAndEditEventHandlers(),qq.DragAndDrop&&qq.supportedFeatures.fileDrop&&(this._dnd=this._setupDragAndDrop()),this._options.paste.targetElement&&this._options.paste.promptForName&&(qq.PasteSupport?this._setupPastePrompt():this.log("Paste support module not found.","error")),this._totalFilesInBatch=0,this._filesInBatchAddedToUi=0)},qq.extend(qq.FineUploader.prototype,qq.basePublicApi),qq.extend(qq.FineUploader.prototype,qq.basePrivateApi),qq.extend(qq.FineUploader.prototype,qq.uiPublicApi),qq.extend(qq.FineUploader.prototype,qq.uiPrivateApi),qq.Templating=function(e){"use strict";var t,n,i,o,r,a,s,l,u="qq-file-id",c="qq-file-id-",d="qq-max-size",p="qq-server-scale",q="qq-hide-dropzone",h="qq-drop-area-text",f="qq-in-progress",m="qq-hidden-forever",g={content:document.createDocumentFragment(),map:{}},_=!1,b=0,v=!1,y=[],S=-1,w={log:null,limits:{maxThumbs:0,timeBetweenThumbs:750},templateIdOrEl:"qq-template",containerEl:null,fileContainerEl:null,button:null,imageGenerator:null,classes:{hide:"qq-hide",editable:"qq-editable"},placeholders:{waitUntilUpdate:!1,thumbnailNotAvailable:null,waitingForThumbnail:null},text:{paused:"Paused"}},F={button:"qq-upload-button-selector",alertDialog:"qq-alert-dialog-selector",dialogCancelButton:"qq-cancel-button-selector",confirmDialog:"qq-confirm-dialog-selector",dialogMessage:"qq-dialog-message-selector",dialogOkButton:"qq-ok-button-selector",promptDialog:"qq-prompt-dialog-selector",uploader:"qq-uploader-selector",drop:"qq-upload-drop-area-selector",list:"qq-upload-list-selector",progressBarContainer:"qq-progress-bar-container-selector",progressBar:"qq-progress-bar-selector",totalProgressBarContainer:"qq-total-progress-bar-container-selector",totalProgressBar:"qq-total-progress-bar-selector",file:"qq-upload-file-selector",spinner:"qq-upload-spinner-selector",size:"qq-upload-size-selector",cancel:"qq-upload-cancel-selector",pause:"qq-upload-pause-selector",continueButton:"qq-upload-continue-selector",deleteButton:"qq-upload-delete-selector",retry:"qq-upload-retry-selector",statusText:"qq-upload-status-text-selector",editFilenameInput:"qq-edit-filename-selector",editNameIcon:"qq-edit-filename-icon-selector",dropText:"qq-upload-drop-area-text-selector",dropProcessing:"qq-drop-processing-selector",dropProcessingSpinner:"qq-drop-processing-spinner-selector",thumbnail:"qq-thumbnail-selector"},x={},C=new qq.Promise,E=new qq.Promise,P=function(){var e=w.placeholders.thumbnailNotAvailable,n=w.placeholders.waitingForThumbnail,i={maxSize:S,scale:l};s&&(e?w.imageGenerator.generate(e,new Image,i).then(function(e){C.success(e)},function(){C.failure(),t("Problem loading 'not available' placeholder image at "+e,"error")}):C.failure(),n?w.imageGenerator.generate(n,new Image,i).then(function(e){E.success(e)},function(){E.failure(),t("Problem loading 'waiting for thumbnail' placeholder image at "+n,"error")}):E.failure())},I=function(e){var t=new qq.Promise;return E.then(function(n){Q(n,e),e.src?t.success():(e.src=n.src,e.onload=function(){e.onload=null,te(e),t.success()})},function(){W(e),t.success()}),t},D=function(e,n,i){var o=X(e);return t("Generating new thumbnail for "+e),n.qqThumbnailId=e,w.imageGenerator.generate(n,o,i).then(function(){b++,te(o),x[e].success()},function(){x[e].failure(),w.placeholders.waitUntilUpdate||Y(e,o)})},U=function(){if(y.length){v=!0;var e=y.shift();e.update?$(e):K(e)}else v=!1},T=function(e){return V(z(e),F.cancel)},A=function(e){return V(z(e),F.continueButton)},B=function(e){return V(r,F[e+"Dialog"])},k=function(e){return V(z(e),F.deleteButton)},R=function(){return V(r,F.dropProcessing)},N=function(e){return V(z(e),F.editNameIcon)},z=function(e){return g.map[e]||qq(a).getFirstByClass(c+e)},L=function(e){return V(z(e),F.file)},O=function(e){return V(z(e),F.pause)},H=function(e){return null==e?V(r,F.totalProgressBarContainer)||V(r,F.totalProgressBar):V(z(e),F.progressBarContainer)||V(z(e),F.progressBar)},M=function(e){return V(z(e),F.retry)},j=function(e){return V(z(e),F.size)},G=function(e){return V(z(e),F.spinner)},V=function(e,t){return e&&qq(e).getFirstByClass(t)},X=function(e){return s&&V(z(e),F.thumbnail)},W=function(e){e&&qq(e).addClass(w.classes.hide)},Q=function(e,t){var n=e.style.maxWidth,i=e.style.maxHeight;i&&n&&!t.style.maxWidth&&!t.style.maxHeight&&qq(t).css({maxWidth:n,maxHeight:i})},Y=function(e,t){var n=x[e]||(new qq.Promise).failure(),i=new qq.Promise;return C.then(function(e){n.then(function(){i.success()},function(){Q(e,t),t.onload=function(){t.onload=null,i.success()},t.src=e.src,te(t)})}),i},J=function(){var e,o,r,a,u,c,f,m,g,_,b;if(t("Parsing template"),null==w.templateIdOrEl)throw new Error("You MUST specify either a template element or ID!");if(qq.isString(w.templateIdOrEl)){if(e=document.getElementById(w.templateIdOrEl),null===e)throw new Error(qq.format("Cannot find template script at ID '{}'!",w.templateIdOrEl));o=e.innerHTML}else{if(void 0===w.templateIdOrEl.innerHTML)throw new Error("You have specified an invalid value for the template option! It must be an ID or an Element.");o=w.templateIdOrEl.innerHTML}if(o=qq.trimStr(o),a=document.createElement("div"),a.appendChild(qq.toElement(o)),b=qq(a).getFirstByClass(F.uploader),w.button&&(c=qq(a).getFirstByClass(F.button),c&&qq(c).remove()),qq.DragAndDrop&&qq.supportedFeatures.fileDrop||(g=qq(a).getFirstByClass(F.dropProcessing),g&&qq(g).remove()),f=qq(a).getFirstByClass(F.drop),f&&!qq.DragAndDrop&&(t("DnD module unavailable.","info"),qq(f).remove()),qq.supportedFeatures.fileDrop?qq(b).hasAttribute(h)&&f&&(_=qq(f).getFirstByClass(F.dropText),_&&qq(_).remove()):(b.removeAttribute(h),f&&qq(f).hasAttribute(q)&&qq(f).css({display:"none"})),m=qq(a).getFirstByClass(F.thumbnail),s?m&&(S=parseInt(m.getAttribute(d)),S=S>0?S:null,l=qq(m).hasAttribute(p)):m&&qq(m).remove(),s=s&&m,n=qq(a).getByClass(F.editFilenameInput).length>0,i=qq(a).getByClass(F.retry).length>0,r=qq(a).getFirstByClass(F.list),null==r)throw new Error("Could not find the file list container in the template!");return u=r.innerHTML,r.innerHTML="",a.getElementsByTagName("DIALOG").length&&document.createElement("dialog"),t("Template parsing complete"),{template:qq.trimStr(a.innerHTML),fileTemplate:qq.trimStr(u)}},Z=function(e,t,n){var i=n,o=i.firstChild;t>0&&(o=qq(i).children()[t].nextSibling),i.insertBefore(e,o)},K=function(e){var t=e.id,n=e.optFileOrBlob,i=n&&n.qqThumbnailId,o=X(t),r={customResizeFunction:e.customResizeFunction,maxSize:S,orient:!0,scale:!0};qq.supportedFeatures.imagePreviews?o?w.limits.maxThumbs&&w.limits.maxThumbs<=b?(Y(t,o),U()):I(o).done(function(){x[t]=new qq.Promise,x[t].done(function(){setTimeout(U,w.limits.timeBetweenThumbs)}),null!=i?ne(t,i):D(t,n,r)}):U():o&&(I(o),U())},$=function(e){var t=e.id,n=e.thumbnailUrl,i=e.showWaitingImg,o=X(t),r={customResizeFunction:e.customResizeFunction,scale:l,maxSize:S};if(o)if(n){if(!(w.limits.maxThumbs&&w.limits.maxThumbs<=b))return i&&I(o),w.imageGenerator.generate(n,o,r).then(function(){te(o),b++,setTimeout(U,w.limits.timeBetweenThumbs)},function(){Y(t,o),setTimeout(U,w.limits.timeBetweenThumbs)});Y(t,o),U()}else Y(t,o),U()},ee=function(e,t){var n=H(e),i=null==e?F.totalProgressBar:F.progressBar;n&&!qq(n).hasClass(i)&&(n=qq(n).getFirstByClass(i)),n&&(qq(n).css({width:t+"%"}),n.setAttribute("aria-valuenow",t))},te=function(e){e&&qq(e).removeClass(w.classes.hide)},ne=function(e,n){var i=X(e),o=X(n);t(qq.format("ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.",e,n,n)),x[n].then(function(){b++,x[e].success(),t(qq.format("Now using previously generated thumbnail created for ID {} on ID {}.",n,e)),i.src=o.src,te(i)},function(){x[e].failure(),w.placeholders.waitUntilUpdate||Y(e,i)})};qq.extend(w,e),t=w.log,qq.supportedFeatures.imagePreviews||(w.limits.timeBetweenThumbs=0,w.limits.maxThumbs=0),r=w.containerEl,s=void 0!==w.imageGenerator,o=J(),P(),qq.extend(this,{render:function(){t("Rendering template in DOM."),b=0,r.innerHTML=o.template,W(R()),this.hideTotalProgress(),a=w.fileContainerEl||V(r,F.list),t("Template rendering complete")},renderFailure:function(e){var t=qq.toElement(e);r.innerHTML="",r.appendChild(t)},reset:function(){this.render()},clearFiles:function(){a.innerHTML=""},disableCancel:function(){_=!0},addFile:function(e,t,n,i,s){var l,d=qq.toElement(o.fileTemplate),p=V(d,F.file),q=V(r,F.uploader),f=s?g.content:a;s&&(g.map[e]=d),qq(d).addClass(c+e),q.removeAttribute(h),p&&(qq(p).setText(t),p.setAttribute("title",t)),d.setAttribute(u,e),n?Z(d,n.index,f):f.appendChild(d),i?(d.style.display="none",qq(d).addClass(m)):(W(H(e)),W(j(e)),W(k(e)),W(M(e)),W(O(e)),W(A(e)),_&&this.hideCancel(e),l=X(e),l&&!l.src&&E.then(function(e){l.src=e.src,e.style.maxHeight&&e.style.maxWidth&&qq(l).css({maxHeight:e.style.maxHeight,maxWidth:e.style.maxWidth}),te(l)}))},addFileToCache:function(e,t,n,i){this.addFile(e,t,n,i,!0)},addCacheToDom:function(){a.appendChild(g.content),g.content=document.createDocumentFragment(),g.map={}},removeFile:function(e){qq(z(e)).remove()},getFileId:function(e){var t=e;if(t){for(;null==t.getAttribute(u);)t=t.parentNode;return parseInt(t.getAttribute(u))}},getFileList:function(){return a},markFilenameEditable:function(e){var t=L(e);t&&qq(t).addClass(w.classes.editable)},updateFilename:function(e,t){var n=L(e);n&&(qq(n).setText(t),n.setAttribute("title",t))},hideFilename:function(e){W(L(e))},showFilename:function(e){te(L(e))},isFileName:function(e){return qq(e).hasClass(F.file)},getButton:function(){return w.button||V(r,F.button)},hideDropProcessing:function(){W(R())},showDropProcessing:function(){te(R())},getDropZone:function(){return V(r,F.drop)},isEditFilenamePossible:function(){return n},hideRetry:function(e){W(M(e))},isRetryPossible:function(){return i},showRetry:function(e){te(M(e))},getFileContainer:function(e){return z(e)},showEditIcon:function(e){var t=N(e);t&&qq(t).addClass(w.classes.editable)},isHiddenForever:function(e){return qq(z(e)).hasClass(m)},hideEditIcon:function(e){var t=N(e);t&&qq(t).removeClass(w.classes.editable)},isEditIcon:function(e){return qq(e).hasClass(F.editNameIcon,!0)},getEditInput:function(e){return V(z(e),F.editFilenameInput)},isEditInput:function(e){return qq(e).hasClass(F.editFilenameInput,!0)},updateProgress:function(e,t,n){var i,o=H(e);o&&n>0&&(i=Math.round(t/n*100),100===i?W(o):te(o),ee(e,i))},updateTotalProgress:function(e,t){this.updateProgress(null,e,t)},hideProgress:function(e){var t=H(e);t&&W(t)},hideTotalProgress:function(){this.hideProgress()},resetProgress:function(e){ee(e,0),this.hideTotalProgress(e)},resetTotalProgress:function(){this.resetProgress()},showCancel:function(e){if(!_){var t=T(e);t&&qq(t).removeClass(w.classes.hide)}},hideCancel:function(e){W(T(e))},isCancel:function(e){return qq(e).hasClass(F.cancel,!0)},allowPause:function(e){te(O(e)),W(A(e))},uploadPaused:function(e){this.setStatusText(e,w.text.paused),this.allowContinueButton(e),W(G(e))},hidePause:function(e){W(O(e))},isPause:function(e){return qq(e).hasClass(F.pause,!0)},isContinueButton:function(e){return qq(e).hasClass(F.continueButton,!0)},allowContinueButton:function(e){te(A(e)),W(O(e))},uploadContinued:function(e){this.setStatusText(e,""),this.allowPause(e),te(G(e))},showDeleteButton:function(e){te(k(e))},hideDeleteButton:function(e){W(k(e))},isDeleteButton:function(e){return qq(e).hasClass(F.deleteButton,!0)},isRetry:function(e){return qq(e).hasClass(F.retry,!0)},updateSize:function(e,t){var n=j(e);n&&(te(n),qq(n).setText(t))},setStatusText:function(e,t){var n=V(z(e),F.statusText);n&&(null==t?qq(n).clearText():qq(n).setText(t))},hideSpinner:function(e){qq(z(e)).removeClass(f),W(G(e))},showSpinner:function(e){qq(z(e)).addClass(f),te(G(e))},generatePreview:function(e,t,n){this.isHiddenForever(e)||(y.push({id:e,customResizeFunction:n,optFileOrBlob:t}),!v&&U())},updateThumbnail:function(e,t,n,i){this.isHiddenForever(e)||(y.push({customResizeFunction:i,update:!0,id:e,thumbnailUrl:t,showWaitingImg:n}),!v&&U())},hasDialog:function(e){return qq.supportedFeatures.dialogElement&&!!B(e)},showDialog:function(e,t,n){var i=B(e),o=V(i,F.dialogMessage),r=i.getElementsByTagName("INPUT")[0],a=V(i,F.dialogCancelButton),s=V(i,F.dialogOkButton),l=new qq.Promise,u=function(){a.removeEventListener("click",c),s&&s.removeEventListener("click",d),l.failure()},c=function(){a.removeEventListener("click",c),i.close()},d=function(){i.removeEventListener("close",u),s.removeEventListener("click",d),i.close(),l.success(r&&r.value)};return i.addEventListener("close",u),a.addEventListener("click",c),s&&s.addEventListener("click",d),r&&(r.value=n),o.textContent=t,i.showModal(),l}})},qq.UiEventHandler=function(e,t){"use strict";function n(e){i.attach(e,o.eventType,function(e){e=e||window.event;var t=e.target||e.srcElement;o.onHandled(t,e)})}var i=new qq.DisposeSupport,o={eventType:"click",attachTo:null,onHandled:function(e,t){}};qq.extend(this,{addHandler:function(e){n(e)},dispose:function(){i.dispose()}}),qq.extend(t,{getFileIdFromItem:function(e){return e.qqFileId},getDisposeSupport:function(){return i}}),qq.extend(o,e),o.attachTo&&n(o.attachTo)},qq.FileButtonsClickHandler=function(e){"use strict";function t(e,t){qq.each(o,function(n,o){var r,a=n.charAt(0).toUpperCase()+n.slice(1);if(i.templating["is"+a](e))return r=i.templating.getFileId(e),qq.preventDefault(t),i.log(qq.format("Detected valid file button click event on file '{}', ID: {}.",i.onGetName(r),r)),o(r),!1})}var n={},i={templating:null,log:function(e,t){},onDeleteFile:function(e){},onCancel:function(e){},onRetry:function(e){},onPause:function(e){},onContinue:function(e){},onGetName:function(e){}},o={cancel:function(e){i.onCancel(e)},retry:function(e){i.onRetry(e)},deleteButton:function(e){i.onDeleteFile(e)},pause:function(e){i.onPause(e)},continueButton:function(e){i.onContinue(e)}};qq.extend(i,e),i.eventType="click",i.onHandled=t,i.attachTo=i.templating.getFileList(),qq.extend(this,new qq.UiEventHandler(i,n))},qq.FilenameClickHandler=function(e){"use strict";function t(e,t){if(i.templating.isFileName(e)||i.templating.isEditIcon(e)){var o=i.templating.getFileId(e),r=i.onGetUploadStatus(o);r===qq.status.SUBMITTED&&(i.log(qq.format("Detected valid filename click event on file '{}', ID: {}.",i.onGetName(o),o)),qq.preventDefault(t),n.handleFilenameEdit(o,e,!0))}}var n={},i={templating:null,log:function(e,t){},classes:{file:"qq-upload-file",editNameIcon:"qq-edit-filename-icon"},onGetUploadStatus:function(e){},onGetName:function(e){}};qq.extend(i,e),i.eventType="click",i.onHandled=t,qq.extend(this,new qq.FilenameEditHandler(i,n))},qq.FilenameInputFocusInHandler=function(e,t){"use strict";function n(e,n){if(i.templating.isEditInput(e)){var o=i.templating.getFileId(e),r=i.onGetUploadStatus(o);r===qq.status.SUBMITTED&&(i.log(qq.format("Detected valid filename input focus event on file '{}', ID: {}.",i.onGetName(o),o)),t.handleFilenameEdit(o,e))}}var i={templating:null,onGetUploadStatus:function(e){},log:function(e,t){}};t||(t={}),i.eventType="focusin",i.onHandled=n,qq.extend(i,e),qq.extend(this,new qq.FilenameEditHandler(i,t))},qq.FilenameInputFocusHandler=function(e){"use strict";e.eventType="focus",e.attachTo=null,qq.extend(this,new qq.FilenameInputFocusInHandler(e,{}))},qq.FilenameEditHandler=function(e,t){"use strict";function n(e){var t=s.onGetName(e),n=t.lastIndexOf(".");return n>0&&(t=t.substr(0,n)),t}function i(e){var t=s.onGetName(e);return qq.getExtension(t)}function o(e,t){var n,o=e.value;void 0!==o&&qq.trimStr(o).length>0&&(n=i(t),void 0!==n&&(o=o+"."+n),s.onSetName(t,o)),s.onEditingStatusChange(t,!1)}function r(e,n){t.getDisposeSupport().attach(e,"blur",function(){o(e,n)})}function a(e,n){t.getDisposeSupport().attach(e,"keyup",function(t){var i=t.keyCode||t.which;13===i&&o(e,n)})}var s={templating:null,log:function(e,t){},onGetUploadStatus:function(e){},onGetName:function(e){},onSetName:function(e,t){},onEditingStatusChange:function(e,t){}};qq.extend(s,e),s.attachTo=s.templating.getFileList(),qq.extend(this,new qq.UiEventHandler(s,t)),qq.extend(t,{handleFilenameEdit:function(e,t,i){var o=s.templating.getEditInput(e);s.onEditingStatusChange(e,!0),o.value=n(e),i&&o.focus(),r(o,e),a(o,e)}})},function(){"use strict";qq.azure.FineUploader=function(e){var t={failedUploadTextDisplay:{mode:"custom"}};qq.extend(t,e,!0),qq.FineUploader.call(this,t,"azure")},qq.extend(qq.azure.FineUploader.prototype,qq.azure.FineUploaderBasic.prototype),qq.extend(qq.azure.FineUploader.prototype,qq.uiPublicApi),qq.extend(qq.azure.FineUploader.prototype,qq.uiPrivateApi),qq.extend(qq.azure.FineUploader.prototype,{})}()}(window,window);
+//# sourceMappingURL=azure.jquery.fine-uploader.min.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.min.js.map b/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.min.js.map
new file mode 100644
index 000000000000..fade0852a14f
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/azure.jquery.fine-uploader.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/jquery-plugin.js","../client/js/jquery-dnd.js","../client/js/azure/jquery-plugin.js","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/azure/util.js","../client/js/non-traditional-common/uploader.basic.api.js","../client/js/azure/uploader.basic.js","../client/js/azure/azure.xhr.upload.handler.js","../client/js/azure/get-sas.js","../client/js/uploadsuccess.ajax.requester.js","../client/js/azure/rest/delete-blob.js","../client/js/azure/rest/put-blob.js","../client/js/azure/rest/put-block.js","../client/js/azure/rest/put-block-list.js","../client/js/dnd.js","../client/js/uploader.api.js","../client/js/uploader.js","../client/js/templating.js","../client/js/ui.handler.events.js","../client/js/ui.handler.click.filebuttons.js","../client/js/ui.handler.click.filename.js","../client/js/ui.handler.focusin.filenameinput.js","../client/js/ui.handler.focus.filenameinput.js","../client/js/ui.handler.edit.filename.js","../client/js/azure/uploader.js"],"names":["global","$","init","options","xformedOpts","transformVariables","newUploaderInstance","getNewUploaderInstance","uploader","addCallbacks","$el","params","uploaderType","pluginOption","namespace","charAt","toUpperCase","slice","toLowerCase","qq","FineUploader","dataStore","key","val","data","undefined","instanceToStore","option","optionVal","transformedOpts","callbacks","each","_options","prop","nonJqueryCallback","name","callbackEventTarget","exec","substring","nonJqueryCallbackRetVal","jqueryEventCallbackRetVal","originalArgs","Array","prototype","call","arguments","transformedArgs","idx","arg","push","maybeWrapInJquery","apply","this","triggerHandler","error","log","message","source","dest","xformed","arrayVals","element","inArray","pluginOptions","isPlainObject","isArray","arrayVal","arrayObjDest","merge","isValidCommand","command","type","match","delegateCommand","retVal","xformedArgs","origArgs","transformedVal","nodeType","cloneNode","fn","fineUploader","optionsOrCommand","self","selfArgs","retVals","index","el","length","jQuery","dropZoneElements","dnd","DragAndDrop","rootDataKey","func","$callbackEl","args","jqueryHandlerResult","fineUploaderDnd","fineUploaderAzure","endpointType","hide","style","display","attach","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","getFirstByClass","children","child","firstChild","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","getAttribute","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","intArray","mimeString","createBlob","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","split","indexOf","atob","decodeURI","ArrayBuffer","Uint8Array","character","charCodeAt","level","console","isObject","variable","Object","toString","isFunction","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","newStr","nextIdxToReplace","strBefore","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","override","target","sourceFn","super_","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","Storage","getItem","bind","oldFunc","context","newArgs","concat","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","testSupportsFileInputElement","tempInput","supported","disabled","ex","isChrome21OrHigher","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","createInput","BUTTON_ID_ATTR_NAME","buttonId","title","setMultiple","folders","acceptFiles","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","disposeSupport","onChange","hoverClass","focusClass","ios8BrowserCrashWorkaround","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","byUuid","getDataByStatus","status","statusResults","statuses","statusEnum","statusResultIndexes","byStatus","dataIndex","byProxyGroupId","byBatchId","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","fileOrUrl","promiseToReturn","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","allowedExtensions","accept","validation","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","replacement","extensionsForMessage","placeholderMatch","messages","names","validationBase","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","requestData","dequeue","nextId","queue","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","mandatedParams","optXhr","url","payload","onSend","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","shouldParamsBeInQueryString","contentType","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","acceptHeader","setRequestHeader","allowXRequestedWithAndCacheControl","responseCode","successfulResponseCodes","prepareToSend","validMethods","DELETE","PATCH","POST","PUT","GET","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","preventRetryResponse","controller","chunkingPossible","concurrentChunkingPossible","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","inProgressIdx","responseToReport","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","expungeFile","detachLoadEvents","isCors","postMessageCallbackTimers","corsMessageReceiver","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","onloadCallbacks","onloadCallback","_parseJsonResponse","_detachLoadEvent","formHandlerInstanceId","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","xhrId","ajaxRequester","_getAjaxRequester","chunkFiles","resumeEnabled","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","getMandatedParams","_method","requester","detectSubsampling","img","ctx","iw","naturalWidth","ih","naturalHeight","width","getContext","drawImage","getImageData","detectVerticalSquash","alpha","ratio","sy","ey","py","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","tmpCtx","sx","dx","d","tmpCanvas","vertSquashRatio","dw","dh","dy","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","opt","imgWidth","imgHeight","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetProtocol","targetHostname","targetPort","targetAnchor","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","TAG_IDS","vals","tagValHex","tagValLength","idHex","tagsToFindIdx","TAG_INFO","274","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","chr1","chr2","enc1","enc2","enc3","output","chr3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","isImage","registerPasteHandler","detachPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","determineNewEndpoint","formEl","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","_form2Obj","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","azure","util","AZURE_PARAM_PREFIX","_paramNameMatchesAzureParameter","_getPrefixedParamName","getParamsAsHeaders","headerName","parseAzureError","codeTag","messageTag","domParser","DOMParser","responseDoc","parseFromString","errorTag","errorDetails","nonTraditionalBasePublicApi","setUploadSuccessParams","_uploadSuccessParamsStore","setUploadSuccessEndpoint","_uploadSuccessEndpointStore","nonTraditionalBasePrivateApi","submitSuccessRequest","successAjaxRequester","onCompleteArgs","successEndpoint","successCustomHeaders","uploadSuccess","successMethod","uploadSuccessParams","fileParams","onSuccessFromServer","successRequestResult","_failedSuccessRequestCallbacks","onFailureFromServer","UploadSuccessAjaxRequester","_getEndpointSpecificParams","sendSuccessRequest","successRequestCallback","signature","blobProperties","minFileSize","_cannedBlobNames","getBlobName","onGetBlobName","_determineBlobName","deleteBlob","_deleteBlob","blobNameOptionValue","fileExtension","blobNameToUse","blobName","relatedToCancel","deleteBlobSasUri","blobUriStore","deleteFileEndpointStore","getSasSuccess","sasUri","getSasFailure","DeleteBlob","getSas","GetSas","restRequestVerb","combineChunks","getSignedUrl","mimeType","blockIdEntries","putBlockList","determineBlobUrl","containerUrl","getBlobNameSuccess","getBlobNameFailure","getSasId","getSasXhr","determineBlobUrlSuccess","blobUrl","getSasForPutBlobOrBlock","determineBlobUrlFailure","azureError","minFileSizeForChunking","getBlobMetadata","putBlob","PutBlob","putBlock","PutBlock","PutBlockList","blockIdEntry","chunkingData","maybePossible","sasResponseReceived","requestPromises","blobUri","requestPromise","restVerb","bloburi","handleSuccessResponse","parsedResponse","pendingRequests","responseJson","successIndicator","failureIndicator","codes","endpoints","promises","endpointHandler","Content-Type","createBlockId","partNum","digits","zeros","paddedPartNum","btoa","blockId","createRequestBody","doc","implementation","createDocument","latestEl","latestTextEl","createTextNode","XMLSerializer","serializeToString","fileMimeType","registerXhrCallback","blockIdsXml","x-ms-blob-content-type","uploadDroppedFiles","uploadDropZone","filesAsArray","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","parseEntryPromise","fullPath","indexOfNameInFullPath","qqPath","droppedFiles","fileError","isDirectory","getFilesInDirectory","entriesLeft","accumEntries","existingPromise","dirReader","createReader","readEntries","newEntries","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","allowMultipleItems","dropError","setupDropzone","dropArea","dropZone","UploadDropZone","HIDE_ZONES_EVENT_NAME","onEnter","dropActive","stopPropagation","onLeaveNotDescendants","onDrop","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","relatedTarget","y","setupDragDrop","dropZones","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","targetEl","errorSpecifics","dragoverShouldBeCanceled","disableDropOutside","dropOutsideDisabled","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","isOrSetDropDisabled","isDisabled","preventDrop","triggerHidezonesEvent","triggerUsingOldApi","hideZonesEvent","createEvent","initEvent","CustomEvent","dispatchEvent","attachEvents","effect","elementFromPoint","clientX","clientY","uiPublicApi","_parent","_templating","addCacheToDom","clearFiles","addExtraDropzone","_dnd","removeExtraDropzone","getItemByFileId","isHiddenForever","getFileContainer","_setupDragAndDrop","_totalFilesInBatch","_filesInBatchAddedToUi","_setupClickAndEditEventHandlers","formattedFilename","updateFilename","uploadPaused","continued","uploadContinued","getId","fileContainerOrChildEl","getFileId","getDropTarget","qqDropTarget","uiPrivateApi","_removeFileItem","removeFile","_fileButtonsClickHandler","FileButtonsClickHandler","_bindFileButtonsClickEvent","_focusinEventSupported","_isEditFilenameEnabled","_filenameClickHandler","_bindFilenameClickEvent","_filenameInputFocusInHandler","_bindFilenameInputFocusInEvent","_filenameInputFocusHandler","_bindFilenameInputFocusEvent","dragAndDrop","extraDropzones","templating","defaultDropZone","getDropZone","showDropProcessing","hideDropProcessing","errorData","lvl","onDeleteFile","onRetry","onPause","onContinue","onGetName","isEditFilenamePossible","FilenameClickHandler","FilenameInputFocusHandler","_filenameEditHandler","onGetUploadStatus","onSetName","onEditingStatusChange","isEditing","qqInput","getEditInput","qqFileContainer","hideFilename","hideEditIcon","showFilename","showEditIcon","markFilenameEditable","hideRetry","setStatusText","_classes","retrying","hidePause","FilenameInputFocusInHandler","hideSpinner","resetTotalProgress","reportDirectoryPaths","qqpath","_addToList","addHandler","updateProgress","hideCancel","hideProgress","waitingForResponse","_displayFileSize","completeUpload","_markFileAsSuccessful","fail","showCancel","isRetryPossible","showRetry","_controlFailureTextDisplay","parentRetVal","newResult","showDeleteButton","_maybeUpdateThumbnail","showSpinner","allowPause","retryNumForDisplay","maxAuto","retryNote","_showCancelLink","showAutoRetryNote","autoRetryNote","resetProgress","_onSubmitDeleteSuccess","forceConfirm","_showDeleteConfirm","_sendDeleteRequest","deletingFailedText","hideDeleteButton","deletingStatusText","confirmMessage","deleteRequestArgs","showConfirm","canned","prependData","prependIndex","dontDisplay","hideScaled","prependFiles","disableCancel","_handledProxyGroup","_clearList","addFileToCache","updateThumbnail","thumbnails","generatePreview","fileSizeOnSubmit","loadedSize","sizeForDisplay","_formatProgress","uploadedSize","formatProgress","mode","responseProperty","failureReason","failedUploadTextDisplay","failUpload","enableTooltip","_showTooltip","showMessage","_setupPastePrompt","namePromptMessage","defaultVal","showPrompt","fileStatus","placeholders","waitUntilResponse","listElement","template","editable","tooManyFilesError","unsupportedBrowser","promptForName","maxCount","notAvailablePath","waitingPath","timeBetweenThumbs","hasDialog","showDialog","confirm","defaultValue","prompt","Templating","templateIdOrEl","containerEl","fileContainerEl","maxThumbs","waitUntilUpdate","thumbnailNotAvailable","waitingForThumbnail","renderFailure","isEditElementsExist","isRetryElementExist","templateHtml","showThumbnails","serverScale","FILE_ID_ATTR","FILE_CLASS_PREFIX","THUMBNAIL_MAX_SIZE_ATTR","THUMBNAIL_SERVER_SCALE_ATTR","HIDE_DROPZONE_ATTR","DROPZPONE_TEXT_ATTR","IN_PROGRESS_CLASS","HIDDEN_FOREVER_CLASS","fileBatch","content","createDocumentFragment","map","isCancelDisabled","generatedThumbnails","thumbnailQueueMonitorRunning","thumbGenerationQueue","thumbnailMaxSize","selectorClasses","alertDialog","dialogCancelButton","confirmDialog","dialogMessage","dialogOkButton","promptDialog","drop","list","progressBarContainer","totalProgressBarContainer","totalProgressBar","spinner","continueButton","deleteButton","statusText","editFilenameInput","editNameIcon","dropText","dropProcessing","dropProcessingSpinner","thumbnail","previewGeneration","cachedThumbnailNotAvailableImg","cachedWaitingForThumbnailImg","cacheThumbnailPlaceholders","notAvailableUrl","waitingUrl","updatedImg","displayWaitingImg","waitingImgPlacement","maybeScalePlaceholderViaCss","show","generateNewPreview","getThumbnail","qqThumbnailId","maybeSetDisplayNotAvailableImg","generateNextQueuedPreview","queuedThumbRequest","update","processUpdateQueuedPreviewRequest","processNewQueuedPreviewRequest","getCancel","getTemplateEl","getContinue","getDialog","getDelete","getDropProcessing","getEditIcon","getPause","getProgress","getRetry","getSpinner","cssClass","previewing","notAvailableImgPlacement","parseAndGetTemplate","scriptEl","scriptHtml","fileListNode","tempTemplateEl","fileListHtml","defaultButton","dropTextEl","uploaderEl","fileTemplate","prependFile","parentEl","beforeEl","optFileOrBlob","relatedThumbnailId","useCachedPreview","showWaitingImg","setProgressBarWidth","percent","bar","progressBarSelector","targetThumbnailId","cachedThumbnailId","targetThumbnail","cachedThumbnail","hideTotalProgress","cantRenderEl","prependInfo","hideForever","batch","thumb","fileEl","fileNameEl","waitingImg","currentNode","getFileList","filenameEl","isFileName","icon","isEditIcon","isEditInput","isCancel","allowContinueButton","isPause","isContinueButton","isDeleteButton","isRetry","textEl","dialog","messageEl","inputEl","cancelBtn","okBtn","closeHandler","cancelClickHandler","okClickHandler","close","showModal","UiEventHandler","s","protectedApi","eventType","srcElement","onHandled","attachTo","getFileIdFromItem","qqFileId","getDisposeSupport","examineEvent","buttonHandlers","buttonType","firstLetterCapButtonType","inheritedInternalApi","handleFilenameEdit","FilenameEditHandler","handleInputFocus","getFilenameSansExtension","filenameSansExt","getOriginalExtension","origName","handleNameUpdate","newFilenameInputEl","origExtension","registerInputBlurHandler","registerInputEnterKeyHandler","keyCode","which","focusInput","focus"],"mappings":"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","file":"azure.jquery.fine-uploader.min.js","sourcesContent":[null,"/*globals jQuery, qq*/\n(function($) {\n \"use strict\";\n var $el,\n pluginOptions = [\"uploaderType\", \"endpointType\"];\n\n function init(options) {\n var xformedOpts = transformVariables(options || {}),\n newUploaderInstance = getNewUploaderInstance(xformedOpts);\n\n uploader(newUploaderInstance);\n addCallbacks(xformedOpts, newUploaderInstance);\n\n return $el;\n }\n\n function getNewUploaderInstance(params) {\n var uploaderType = pluginOption(\"uploaderType\"),\n namespace = pluginOption(\"endpointType\");\n\n // If the integrator has defined a specific type of uploader to load, use that, otherwise assume `qq.FineUploader`\n if (uploaderType) {\n // We can determine the correct constructor function to invoke by combining \"FineUploader\"\n // with the upper camel cased `uploaderType` value.\n uploaderType = uploaderType.charAt(0).toUpperCase() + uploaderType.slice(1).toLowerCase();\n\n if (namespace) {\n return new qq[namespace][\"FineUploader\" + uploaderType](params);\n }\n\n return new qq[\"FineUploader\" + uploaderType](params);\n }\n else {\n if (namespace) {\n return new qq[namespace].FineUploader(params);\n }\n\n return new qq.FineUploader(params);\n }\n }\n\n function dataStore(key, val) {\n var data = $el.data(\"fineuploader\");\n\n if (val) {\n if (data === undefined) {\n data = {};\n }\n data[key] = val;\n $el.data(\"fineuploader\", data);\n }\n else {\n if (data === undefined) {\n return null;\n }\n return data[key];\n }\n }\n\n //the underlying Fine Uploader instance is stored in jQuery's data stored, associated with the element\n // tied to this instance of the plug-in\n function uploader(instanceToStore) {\n return dataStore(\"uploader\", instanceToStore);\n }\n\n function pluginOption(option, optionVal) {\n return dataStore(option, optionVal);\n }\n\n // Implement all callbacks defined in Fine Uploader as functions that trigger appropriately names events and\n // return the result of executing the bound handler back to Fine Uploader\n function addCallbacks(transformedOpts, newUploaderInstance) {\n var callbacks = transformedOpts.callbacks = {};\n\n $.each(newUploaderInstance._options.callbacks, function(prop, nonJqueryCallback) {\n var name, callbackEventTarget;\n\n name = /^on(\\w+)/.exec(prop)[1];\n name = name.substring(0, 1).toLowerCase() + name.substring(1);\n callbackEventTarget = $el;\n\n callbacks[prop] = function() {\n var originalArgs = Array.prototype.slice.call(arguments),\n transformedArgs = [],\n nonJqueryCallbackRetVal, jqueryEventCallbackRetVal;\n\n $.each(originalArgs, function(idx, arg) {\n transformedArgs.push(maybeWrapInJquery(arg));\n });\n\n nonJqueryCallbackRetVal = nonJqueryCallback.apply(this, originalArgs);\n\n try {\n jqueryEventCallbackRetVal = callbackEventTarget.triggerHandler(name, transformedArgs);\n }\n catch (error) {\n qq.log(\"Caught error in Fine Uploader jQuery event handler: \" + error.message, \"error\");\n }\n\n /*jshint -W116*/\n if (nonJqueryCallbackRetVal != null) {\n return nonJqueryCallbackRetVal;\n }\n return jqueryEventCallbackRetVal;\n };\n });\n\n newUploaderInstance._options.callbacks = callbacks;\n }\n\n //transform jQuery objects into HTMLElements, and pass along all other option properties\n function transformVariables(source, dest) {\n var xformed, arrayVals;\n\n if (dest === undefined) {\n if (source.uploaderType !== \"basic\") {\n xformed = { element: $el[0] };\n }\n else {\n xformed = {};\n }\n }\n else {\n xformed = dest;\n }\n\n $.each(source, function(prop, val) {\n if ($.inArray(prop, pluginOptions) >= 0) {\n pluginOption(prop, val);\n }\n else if (val instanceof $) {\n xformed[prop] = val[0];\n }\n else if ($.isPlainObject(val)) {\n xformed[prop] = {};\n transformVariables(val, xformed[prop]);\n }\n else if ($.isArray(val)) {\n arrayVals = [];\n $.each(val, function(idx, arrayVal) {\n var arrayObjDest = {};\n\n if (arrayVal instanceof $) {\n $.merge(arrayVals, arrayVal);\n }\n else if ($.isPlainObject(arrayVal)) {\n transformVariables(arrayVal, arrayObjDest);\n arrayVals.push(arrayObjDest);\n }\n else {\n arrayVals.push(arrayVal);\n }\n });\n xformed[prop] = arrayVals;\n }\n else {\n xformed[prop] = val;\n }\n });\n\n if (dest === undefined) {\n return xformed;\n }\n }\n\n function isValidCommand(command) {\n return $.type(command) === \"string\" &&\n !command.match(/^_/) && //enforce private methods convention\n uploader()[command] !== undefined;\n }\n\n // Assuming we have already verified that this is a valid command, call the associated function in the underlying\n // Fine Uploader instance (passing along the arguments from the caller) and return the result of the call back to the caller\n function delegateCommand(command) {\n var xformedArgs = [],\n origArgs = Array.prototype.slice.call(arguments, 1),\n retVal;\n\n transformVariables(origArgs, xformedArgs);\n\n retVal = uploader()[command].apply(uploader(), xformedArgs);\n\n return maybeWrapInJquery(retVal);\n }\n\n // If the value is an `HTMLElement` or `HTMLDocument`, wrap it in a `jQuery` object\n function maybeWrapInJquery(val) {\n var transformedVal = val;\n\n // If the command is returning an `HTMLElement` or `HTMLDocument`, wrap it in a `jQuery` object\n /*jshint -W116*/\n if (val != null && typeof val === \"object\" &&\n (val.nodeType === 1 || val.nodeType === 9) && val.cloneNode) {\n\n transformedVal = $(val);\n }\n\n return transformedVal;\n }\n\n $.fn.fineUploader = function(optionsOrCommand) {\n var self = this, selfArgs = arguments, retVals = [];\n\n this.each(function(index, el) {\n $el = $(el);\n\n if (uploader() && isValidCommand(optionsOrCommand)) {\n retVals.push(delegateCommand.apply(self, selfArgs));\n\n if (self.length === 1) {\n return false;\n }\n }\n else if (typeof optionsOrCommand === \"object\" || !optionsOrCommand) {\n init.apply(self, selfArgs);\n }\n else {\n $.error(\"Method \" + optionsOrCommand + \" does not exist on jQuery.fineUploader\");\n }\n });\n\n if (retVals.length === 1) {\n return retVals[0];\n }\n else if (retVals.length > 1) {\n return retVals;\n }\n\n return this;\n };\n\n}(jQuery));\n","/*globals jQuery, qq*/\n(function($) {\n \"use strict\";\n var rootDataKey = \"fineUploaderDnd\",\n $el;\n\n function init(options) {\n if (!options) {\n options = {};\n }\n\n options.dropZoneElements = [$el];\n var xformedOpts = transformVariables(options);\n addCallbacks(xformedOpts);\n dnd(new qq.DragAndDrop(xformedOpts));\n\n return $el;\n }\n\n function dataStore(key, val) {\n var data = $el.data(rootDataKey);\n\n if (val) {\n if (data === undefined) {\n data = {};\n }\n data[key] = val;\n $el.data(rootDataKey, data);\n }\n else {\n if (data === undefined) {\n return null;\n }\n return data[key];\n }\n }\n\n function dnd(instanceToStore) {\n return dataStore(\"dndInstance\", instanceToStore);\n }\n\n function addCallbacks(transformedOpts) {\n var callbacks = transformedOpts.callbacks = {};\n\n $.each(new qq.DragAndDrop.callbacks(), function(prop, func) {\n var name = prop,\n $callbackEl;\n\n $callbackEl = $el;\n\n callbacks[prop] = function() {\n var args = Array.prototype.slice.call(arguments),\n jqueryHandlerResult = $callbackEl.triggerHandler(name, args);\n\n return jqueryHandlerResult;\n };\n });\n }\n\n //transform jQuery objects into HTMLElements, and pass along all other option properties\n function transformVariables(source, dest) {\n var xformed, arrayVals;\n\n if (dest === undefined) {\n xformed = {};\n }\n else {\n xformed = dest;\n }\n\n $.each(source, function(prop, val) {\n if (val instanceof $) {\n xformed[prop] = val[0];\n }\n else if ($.isPlainObject(val)) {\n xformed[prop] = {};\n transformVariables(val, xformed[prop]);\n }\n else if ($.isArray(val)) {\n arrayVals = [];\n $.each(val, function(idx, arrayVal) {\n if (arrayVal instanceof $) {\n $.merge(arrayVals, arrayVal);\n }\n else {\n arrayVals.push(arrayVal);\n }\n });\n xformed[prop] = arrayVals;\n }\n else {\n xformed[prop] = val;\n }\n });\n\n if (dest === undefined) {\n return xformed;\n }\n }\n\n function isValidCommand(command) {\n return $.type(command) === \"string\" &&\n command === \"dispose\" &&\n dnd()[command] !== undefined;\n }\n\n function delegateCommand(command) {\n var xformedArgs = [], origArgs = Array.prototype.slice.call(arguments, 1);\n transformVariables(origArgs, xformedArgs);\n return dnd()[command].apply(dnd(), xformedArgs);\n }\n\n $.fn.fineUploaderDnd = function(optionsOrCommand) {\n var self = this, selfArgs = arguments, retVals = [];\n\n this.each(function(index, el) {\n $el = $(el);\n\n if (dnd() && isValidCommand(optionsOrCommand)) {\n retVals.push(delegateCommand.apply(self, selfArgs));\n\n if (self.length === 1) {\n return false;\n }\n }\n else if (typeof optionsOrCommand === \"object\" || !optionsOrCommand) {\n init.apply(self, selfArgs);\n }\n else {\n $.error(\"Method \" + optionsOrCommand + \" does not exist in Fine Uploader's DnD module.\");\n }\n });\n\n if (retVals.length === 1) {\n return retVals[0];\n }\n else if (retVals.length > 1) {\n return retVals;\n }\n\n return this;\n };\n\n}(jQuery));\n","/*globals jQuery*/\n/**\n * Simply an alias for the `fineUploader` plug-in wrapper, but hides the required `endpointType` option from the\n * integrator. I thought it may be confusing to convey to the integrator that, when using Fine Uploader in Azure mode,\n * you need to specify an `endpointType` with a value of \"azure\", and perhaps an `uploaderType` with a value of \"basic\" if\n * you want to use basic mode when uploading directly to Azure as well. So, you can use this plug-in alias and not worry\n * about the `endpointType` option at all.\n */\n(function($) {\n \"use strict\";\n\n $.fn.fineUploaderAzure = function(optionsOrCommand) {\n if (typeof optionsOrCommand === \"object\") {\n\n // This option is used to tell the plug-in wrapper to instantiate the appropriate Azure-namespace modules.\n optionsOrCommand.endpointType = \"azure\";\n }\n\n return $.fn.fineUploader.apply(this, arguments);\n };\n\n}(jQuery));\n","/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\"\"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq */\nqq.azure = qq.azure || {};\nqq.azure.util = qq.azure.util || (function() {\n \"use strict\";\n\n return {\n AZURE_PARAM_PREFIX: \"x-ms-meta-\",\n\n /** Test if a request header is actually a known Azure parameter. See: https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx\n *\n * @param name Name of the Request Header parameter.\n * @returns {Boolean} Test result.\n */\n _paramNameMatchesAzureParameter: function(name) {\n switch (name) {\n case \"Cache-Control\":\n case \"Content-Disposition\":\n case \"Content-Encoding\":\n case \"Content-MD5\":\n case \"x-ms-blob-content-encoding\":\n case \"x-ms-blob-content-disposition\":\n case \"x-ms-blob-content-md5\":\n case \"x-ms-blob-cache-control\":\n return true;\n default:\n return false;\n }\n },\n\n /** Create Prefixed request headers which are appropriate for Azure.\n *\n * If the request header is appropriate for Azure (e.g. Cache-Control) then it should be\n * passed along without a metadata prefix. For all other request header parameter names,\n * qq.azure.util.AZURE_PARAM_PREFIX should be prepended.\n *\n * @param name Name of the Request Header parameter to construct a (possibly) prefixed name.\n * @returns {String} A valid Request Header parameter name.\n */\n _getPrefixedParamName: function(name) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n return name;\n }\n else {\n return qq.azure.util.AZURE_PARAM_PREFIX + name;\n }\n },\n\n getParamsAsHeaders: function(params) {\n var headers = {};\n\n qq.each(params, function(name, val) {\n var headerName = qq.azure.util._getPrefixedParamName(name),\n value = null;\n\n if (qq.isFunction(val)) {\n value = String(val());\n }\n else if (qq.isObject(val)) {\n qq.extend(headers, qq.azure.util.getParamsAsHeaders(val));\n }\n else {\n value = String(val);\n }\n\n if (value !== null) {\n if (qq.azure.util._paramNameMatchesAzureParameter(name)) {\n headers[headerName] = value;\n } else {\n headers[headerName] = encodeURIComponent(value);\n }\n }\n });\n\n return headers;\n },\n\n parseAzureError: function(responseText, log) {\n var domParser = new DOMParser(),\n responseDoc = domParser.parseFromString(responseText, \"application/xml\"),\n errorTag = responseDoc.getElementsByTagName(\"Error\")[0],\n errorDetails = {},\n codeTag, messageTag;\n\n log(\"Received error response: \" + responseText, \"error\");\n\n if (errorTag) {\n messageTag = errorTag.getElementsByTagName(\"Message\")[0];\n if (messageTag) {\n errorDetails.message = messageTag.textContent;\n }\n\n codeTag = errorTag.getElementsByTagName(\"Code\")[0];\n if (codeTag) {\n errorDetails.code = codeTag.textContent;\n }\n\n log(\"Parsed Azure error: \" + JSON.stringify(errorDetails), \"error\");\n\n return errorDetails;\n }\n }\n };\n}());\n","/*globals qq*/\n/**\n * Defines the public API for non-traditional FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.nonTraditionalBasePublicApi = {\n setUploadSuccessParams: function(params, id) {\n this._uploadSuccessParamsStore.set(params, id);\n },\n setUploadSuccessEndpoint: function(endpoint, id) {\n this._uploadSuccessEndpointStore.set(endpoint, id);\n }\n };\n\n qq.nonTraditionalBasePrivateApi = {\n /**\n * When the upload has completed, if it is successful, send a request to the `successEndpoint` (if defined).\n * This will hold up the call to the `onComplete` callback until we have determined success of the upload\n * according to the local server, if a `successEndpoint` has been defined by the integrator.\n *\n * @param id ID of the completed upload\n * @param name Name of the associated item\n * @param result Object created from the server's parsed JSON response.\n * @param xhr Associated XmlHttpRequest, if this was used to send the request.\n * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise`\n * if we need to ask the server.\n * @private\n */\n _onComplete: function(id, name, result, xhr) {\n var success = result.success ? true : false,\n self = this,\n onCompleteArgs = arguments,\n successEndpoint = this._uploadSuccessEndpointStore.get(id),\n successCustomHeaders = this._options.uploadSuccess.customHeaders,\n successMethod = this._options.uploadSuccess.method,\n cors = this._options.cors,\n promise = new qq.Promise(),\n uploadSuccessParams = this._uploadSuccessParamsStore.get(id),\n fileParams = this._paramsStore.get(id),\n\n // If we are waiting for confirmation from the local server, and have received it,\n // include properties from the local server response in the `response` parameter\n // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and\n // fulfill the associated promise.\n onSuccessFromServer = function(successRequestResult) {\n delete self._failedSuccessRequestCallbacks[id];\n qq.extend(result, successRequestResult);\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.success(successRequestResult);\n },\n\n // If the upload success request fails, attempt to re-send the success request (via the core retry code).\n // The entire upload may be restarted if the server returns a \"reset\" property with a value of true as well.\n onFailureFromServer = function(successRequestResult) {\n var callback = submitSuccessRequest;\n\n qq.extend(result, successRequestResult);\n\n if (result && result.reset) {\n callback = null;\n }\n\n if (!callback) {\n delete self._failedSuccessRequestCallbacks[id];\n }\n else {\n self._failedSuccessRequestCallbacks[id] = callback;\n }\n\n if (!self._onAutoRetry(id, name, result, xhr, callback)) {\n qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs);\n promise.failure(successRequestResult);\n }\n },\n submitSuccessRequest,\n successAjaxRequester;\n\n // Ask the local server if the file sent is ok.\n if (success && successEndpoint) {\n successAjaxRequester = new qq.UploadSuccessAjaxRequester({\n endpoint: successEndpoint,\n method: successMethod,\n customHeaders: successCustomHeaders,\n cors: cors,\n log: qq.bind(this.log, this)\n });\n\n // combine custom params and default params\n qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true);\n\n // include any params associated with the file\n fileParams && qq.extend(uploadSuccessParams, fileParams, true);\n\n submitSuccessRequest = qq.bind(function() {\n successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams)\n .then(onSuccessFromServer, onFailureFromServer);\n }, self);\n\n submitSuccessRequest();\n\n return promise;\n }\n\n // If we are not asking the local server about the file, just delegate to the parent `_onComplete`.\n return qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);\n },\n\n // If the failure occurred on an upload success request (and a reset was not ordered), try to resend that instead.\n _manualRetry: function(id) {\n var successRequestCallback = this._failedSuccessRequestCallbacks[id];\n\n return qq.FineUploaderBasic.prototype._manualRetry.call(this, id, successRequestCallback);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploaderBasic mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader Basic as well as code to handle uploads directly to Azure.\n * Some inherited options and API methods have a special meaning in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploaderBasic = function(o) {\n if (!qq.supportedFeatures.ajaxUploading) {\n throw new qq.Error(\"Uploading directly to Azure is not possible in this browser.\");\n }\n\n var options = {\n signature: {\n endpoint: null,\n\n customHeaders: {}\n },\n\n // 'uuid', 'filename', or a function which may be promissory\n blobProperties: {\n name: \"uuid\"\n },\n\n uploadSuccess: {\n endpoint: null,\n\n method: \"POST\",\n\n // In addition to the default params sent by Fine Uploader\n params: {},\n\n customHeaders: {}\n },\n\n chunking: {\n // If this is increased, Azure may respond with a 413\n partSize: 4000000,\n // Don't chunk files less than this size\n minFileSize: 4000001\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Call base module\n qq.FineUploaderBasic.call(this, options);\n\n this._uploadSuccessParamsStore = this._createStore(this._options.uploadSuccess.params);\n this._uploadSuccessEndpointStore = this._createStore(this._options.uploadSuccess.endpoint);\n\n // This will hold callbacks for failed uploadSuccess requests that will be invoked on retry.\n // Indexed by file ID.\n this._failedSuccessRequestCallbacks = {};\n\n // Holds blob names for file representations constructed from a session request.\n this._cannedBlobNames = {};\n };\n\n // Inherit basic public & private API methods.\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.basePrivateApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePublicApi);\n qq.extend(qq.azure.FineUploaderBasic.prototype, qq.nonTraditionalBasePrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploaderBasic.prototype, {\n getBlobName: function(id) {\n /* jshint eqnull:true */\n if (this._cannedBlobNames[id] == null) {\n return this._handler.getThirdPartyFileId(id);\n }\n return this._cannedBlobNames[id];\n },\n\n _getEndpointSpecificParams: function(id) {\n return {\n blob: this.getBlobName(id),\n uuid: this.getUuid(id),\n name: this.getName(id),\n container: this._endpointStore.get(id)\n };\n },\n\n _createUploadHandler: function() {\n return qq.FineUploaderBasic.prototype._createUploadHandler.call(this,\n {\n signature: this._options.signature,\n onGetBlobName: qq.bind(this._determineBlobName, this),\n deleteBlob: qq.bind(this._deleteBlob, this, true)\n },\n \"azure\");\n },\n\n _determineBlobName: function(id) {\n var self = this,\n blobNameOptionValue = this._options.blobProperties.name,\n uuid = this.getUuid(id),\n filename = this.getName(id),\n fileExtension = qq.getExtension(filename),\n blobNameToUse = uuid;\n\n if (qq.isString(blobNameOptionValue)) {\n switch (blobNameOptionValue) {\n case \"uuid\":\n if (fileExtension !== undefined) {\n blobNameToUse += \".\" + fileExtension;\n }\n return new qq.Promise().success(blobNameToUse);\n case \"filename\":\n return new qq.Promise().success(filename);\n default:\n return new qq.Promise.failure(\"Invalid blobName option value - \" + blobNameOptionValue);\n }\n }\n else {\n return blobNameOptionValue.call(this, id);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id;\n\n /* jshint eqnull:true */\n if (sessionData.blobName == null) {\n throw new qq.Error(\"Did not find blob name property in server session response. This is required!\");\n }\n else {\n id = qq.FineUploaderBasic.prototype._addCannedFile.apply(this, arguments);\n this._cannedBlobNames[id] = sessionData.blobName;\n }\n\n return id;\n },\n\n _deleteBlob: function(relatedToCancel, id) {\n var self = this,\n deleteBlobSasUri = {},\n blobUriStore = {\n get: function(id) {\n return self._endpointStore.get(id) + \"/\" + self.getBlobName(id);\n }\n },\n deleteFileEndpointStore = {\n get: function(id) {\n return deleteBlobSasUri[id];\n }\n },\n getSasSuccess = function(id, sasUri) {\n deleteBlobSasUri[id] = sasUri;\n deleteBlob.send(id);\n },\n getSasFailure = function(id, reason, xhr) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS\", \"error\");\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n }\n else {\n self._onDeleteComplete(id, xhr, true);\n self._options.callbacks.onDeleteComplete(id, xhr, true);\n }\n },\n deleteBlob = new qq.azure.DeleteBlob({\n endpointStore: deleteFileEndpointStore,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n delete deleteBlobSasUri[id];\n\n if (isError) {\n if (relatedToCancel) {\n self.log(\"Will cancel upload, but failed to remove uncommitted parts from Azure.\", \"error\");\n }\n else {\n qq.azure.util.parseAzureError(xhrOrXdr.responseText, qq.bind(self.log, self));\n }\n }\n\n if (relatedToCancel) {\n qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id));\n self.log(\"Deleted uncommitted blob chunks for \" + id);\n }\n else {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n }\n }),\n getSas = new qq.azure.GetSas({\n cors: this._options.cors,\n customHeaders: this._options.signature.customHeaders,\n endpointStore: {\n get: function() {\n return self._options.signature.endpoint;\n }\n },\n restRequestVerb: deleteBlob.method,\n log: qq.bind(self.log, self)\n });\n\n getSas.request(id, blobUriStore.get(id)).then(\n qq.bind(getSasSuccess, self, id),\n qq.bind(getSasFailure, self, id));\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return {\n sendDelete: function(id, uuid) {\n self._deleteBlob(false, id);\n }\n };\n }\n });\n}());\n","/*globals qq */\n/**\n * Upload handler used by the upload to Azure module that depends on File API support, and, therefore, makes use of\n * `XMLHttpRequest` level 2 to upload `File`s and `Blob`s directly to Azure Blob Storage containers via the\n * associated Azure API.\n *\n * @param spec Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\n// TODO l18n for error messages returned to UI\nqq.azure.XhrUploadHandler = function(spec, proxy) {\n \"use strict\";\n\n var handler = this,\n log = proxy.log,\n cors = spec.cors,\n endpointStore = spec.endpointStore,\n paramsStore = spec.paramsStore,\n signature = spec.signature,\n filenameParam = spec.filenameParam,\n minFileSizeForChunking = spec.chunking.minFileSize,\n deleteBlob = spec.deleteBlob,\n onGetBlobName = spec.onGetBlobName,\n getName = proxy.getName,\n getSize = proxy.getSize,\n\n getBlobMetadata = function(id) {\n var params = paramsStore.get(id);\n params[filenameParam] = getName(id);\n return params;\n },\n\n api = {\n putBlob: new qq.azure.PutBlob({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n putBlock: new qq.azure.PutBlock({\n log: log\n }),\n\n putBlockList: new qq.azure.PutBlockList({\n getBlobMetadata: getBlobMetadata,\n log: log\n }),\n\n getSasForPutBlobOrBlock: new qq.azure.GetSas({\n cors: cors,\n customHeaders: signature.customHeaders,\n endpointStore: {\n get: function() {\n return signature.endpoint;\n }\n },\n log: log,\n restRequestVerb: \"PUT\"\n })\n };\n\n function combineChunks(id) {\n var promise = new qq.Promise();\n\n getSignedUrl(id).then(function(sasUri) {\n var mimeType = handler._getMimeType(id),\n blockIdEntries = handler._getPersistableData(id).blockIdEntries;\n\n api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) {\n handler._registerXhr(id, null, xhr, api.putBlockList);\n })\n .then(function(xhr) {\n log(\"Success combining chunks for id \" + id);\n promise.success({}, xhr);\n }, function(xhr) {\n log(\"Attempt to combine chunks failed for id \" + id, \"error\");\n handleFailure(xhr, promise);\n });\n\n },\n promise.failure);\n\n return promise;\n }\n\n function determineBlobUrl(id) {\n var containerUrl = endpointStore.get(id),\n promise = new qq.Promise(),\n getBlobNameSuccess = function(blobName) {\n handler._setThirdPartyFileId(id, blobName);\n promise.success(containerUrl + \"/\" + blobName);\n },\n getBlobNameFailure = function(reason) {\n promise.failure(reason);\n };\n\n onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure);\n\n return promise;\n }\n\n function getSignedUrl(id, optChunkIdx) {\n // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the SAS ajax requester to avoid collisions.\n var getSasId = optChunkIdx == null ? id : id + \".\" + optChunkIdx,\n\n promise = new qq.Promise(),\n getSasSuccess = function(sasUri) {\n log(\"GET SAS request succeeded.\");\n promise.success(sasUri);\n },\n getSasFailure = function(reason, getSasXhr) {\n log(\"GET SAS request failed: \" + reason, \"error\");\n promise.failure({error: \"Problem communicating with local server\"}, getSasXhr);\n },\n determineBlobUrlSuccess = function(blobUrl) {\n api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then(\n getSasSuccess,\n getSasFailure\n );\n },\n determineBlobUrlFailure = function(reason) {\n log(qq.format(\"Failed to determine blob name for ID {} - {}\", id, reason), \"error\");\n promise.failure({error: reason});\n };\n\n determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure);\n\n return promise;\n }\n\n function handleFailure(xhr, promise) {\n var azureError = qq.azure.util.parseAzureError(xhr.responseText, log),\n errorMsg = \"Problem sending file to Azure\";\n\n promise.failure({error: errorMsg,\n azureError: azureError && azureError.message,\n reset: xhr.status === 403\n });\n }\n\n qq.extend(this, {\n uploadChunk: function(id, chunkIdx) {\n var promise = new qq.Promise();\n\n getSignedUrl(id, chunkIdx).then(\n function(sasUri) {\n var xhr = handler._createXhr(id, chunkIdx),\n chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._registerProgressHandler(id, chunkIdx, chunkData.size);\n handler._registerXhr(id, chunkIdx, xhr, api.putBlock);\n\n // We may have multiple put block requests in progress for the same file, so we must include the chunk idx\n // as part of the ID when communicating with the put block ajax requester to avoid collisions.\n api.putBlock.upload(id + \".\" + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then(\n function(blockIdEntry) {\n if (!handler._getPersistableData(id).blockIdEntries) {\n handler._getPersistableData(id).blockIdEntries = [];\n }\n\n handler._getPersistableData(id).blockIdEntries.push(blockIdEntry);\n log(\"Put Block call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(qq.format(\"Put Block call failed for ID {} on part {}\", id, chunkIdx), \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure\n );\n\n return promise;\n },\n\n uploadFile: function(id) {\n var promise = new qq.Promise(),\n fileOrBlob = handler.getFile(id);\n\n getSignedUrl(id).then(function(sasUri) {\n var xhr = handler._createXhr(id);\n\n handler._registerProgressHandler(id);\n\n api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then(\n function() {\n log(\"Put Blob call succeeded for \" + id);\n promise.success({}, xhr);\n },\n function() {\n log(\"Put Blob call failed for \" + id, \"error\");\n handleFailure(xhr, promise);\n }\n );\n },\n promise.failure);\n\n return promise;\n }\n });\n\n qq.extend(this,\n new qq.XhrUploadHandler({\n options: qq.extend({namespace: \"azure\"}, spec),\n proxy: qq.extend({getEndpoint: spec.endpointStore.get}, proxy)\n }\n ));\n\n qq.override(this, function(super_) {\n return {\n expunge: function(id) {\n var relatedToCancel = handler._wasCanceled(id),\n chunkingData = handler._getPersistableData(id),\n blockIdEntries = (chunkingData && chunkingData.blockIdEntries) || [];\n\n if (relatedToCancel && blockIdEntries.length > 0) {\n deleteBlob(id);\n }\n\n super_.expunge(id);\n },\n\n finalizeChunks: function(id) {\n return combineChunks(id);\n },\n\n _shouldChunkThisFile: function(id) {\n var maybePossible = super_._shouldChunkThisFile(id);\n return maybePossible && getSize(id) >= minFileSizeForChunking;\n }\n };\n });\n};\n","/* globals qq */\n/**\n * Sends a GET request to the integrator's server, which should return a Shared Access Signature URI used to\n * make a specific request on a Blob via the Azure REST API.\n */\nqq.azure.GetSas = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n cors: {\n expected: false,\n sendCredentials: false\n },\n customHeaders: {},\n restRequestVerb: \"PUT\",\n endpointStore: null,\n log: function(str, level) {}\n },\n requestPromises = {};\n\n qq.extend(options, o);\n\n function sasResponseReceived(id, xhr, isError) {\n var promise = requestPromises[id];\n\n if (isError) {\n promise.failure(\"Received response code \" + xhr.status, xhr);\n }\n else {\n if (xhr.responseText.length) {\n promise.success(xhr.responseText);\n }\n else {\n promise.failure(\"Empty response.\", xhr);\n }\n }\n\n delete requestPromises[id];\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n successfulResponseCodes: {\n GET: [200]\n },\n contentType: null,\n customHeaders: options.customHeaders,\n endpointStore: options.endpointStore,\n cors: options.cors,\n log: options.log,\n onComplete: sasResponseReceived\n }));\n\n qq.extend(this, {\n request: function(id, blobUri) {\n var requestPromise = new qq.Promise(),\n restVerb = options.restRequestVerb;\n\n options.log(qq.format(\"Submitting GET SAS request for a {} REST request related to file ID {}.\", restVerb, id));\n\n requestPromises[id] = requestPromise;\n\n requester.initTransport(id)\n .withParams({\n bloburi: blobUri,\n _method: restVerb\n })\n .withCacheBuster()\n .send();\n\n return requestPromise;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Sends a POST request to the server to notify it of a successful upload to an endpoint. The server is expected to indicate success\n * or failure via the response status. Specific information about the failure can be passed from the server via an `error`\n * property (by default) in an \"application/json\" response.\n *\n * @param o Options associated with all requests.\n * @constructor\n */\nqq.UploadSuccessAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n pendingRequests = [],\n options = {\n method: \"POST\",\n endpoint: null,\n maxConnections: 3,\n customHeaders: {},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n function handleSuccessResponse(id, xhrOrXdr, isError) {\n var promise = pendingRequests[id],\n responseJson = xhrOrXdr.responseText,\n successIndicator = {success: true},\n failureIndicator = {success: false},\n parsedResponse;\n\n delete pendingRequests[id];\n\n options.log(qq.format(\"Received the following response body to an upload success request for id {}: {}\", id, responseJson));\n\n try {\n parsedResponse = qq.parseJson(responseJson);\n\n // If this is a cross-origin request, the server may return a 200 response w/ error or success properties\n // in order to ensure any specific error message is picked up by Fine Uploader for all browsers,\n // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the\n // response body for an \"error\" response.\n if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) {\n options.log(\"Upload success request was rejected by the server.\", \"error\");\n promise.failure(qq.extend(parsedResponse, failureIndicator));\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(qq.extend(parsedResponse, successIndicator));\n }\n }\n catch (error) {\n // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly.\n if (isError) {\n options.log(qq.format(\"Your server indicated failure in its upload success request response for id {}!\", id), \"error\");\n promise.failure(failureIndicator);\n }\n else {\n options.log(\"Upload success was acknowledged by the server.\");\n promise.success(successIndicator);\n }\n }\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n method: options.method,\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n paramsStore: options.paramsStore,\n maxConnections: options.maxConnections,\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: handleSuccessResponse,\n cors: options.cors\n }));\n\n qq.extend(this, {\n /**\n * Sends a request to the server, notifying it that a recently submitted file was successfully sent.\n *\n * @param id ID of the associated file\n * @param spec `Object` with the properties that correspond to important values that we want to\n * send to the server with this request.\n * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed\n * payload of the response will be passed into the `failure` or `success` promise method.\n */\n sendSuccessRequest: function(id, spec) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting upload success request/notification for \" + id);\n\n requester.initTransport(id)\n .withParams(spec)\n .send();\n\n pendingRequests[id] = promise;\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Delete Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx.\n */\nqq.azure.DeleteBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"DELETE\",\n options = {\n endpointStore: {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhr, isError) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [202];\n return codes;\n }()),\n contentType: null,\n endpointStore: options.endpointStore,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete\n }));\n\n qq.extend(this, {\n method: method,\n send: function(id) {\n options.log(\"Submitting Delete Blob request for \" + id);\n\n return requester.initTransport(id)\n .send();\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Blob Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx.\n */\nqq.azure.PutBlob = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n promises = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id),\n headers = qq.azure.util.getParamsAsHeaders(params);\n\n headers[\"x-ms-blob-type\"] = \"BlockBlob\";\n\n return headers;\n },\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success();\n }\n }\n }));\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, url, file) {\n var promise = new qq.Promise();\n\n options.log(\"Submitting Put Blob request for \" + id);\n\n promises[id] = promise;\n endpoints[id] = url;\n\n requester.initTransport(id)\n .withPayload(file)\n .withHeaders({\"Content-Type\": file.type})\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx.\n */\nqq.azure.PutBlock = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n blockIdEntries = {},\n promises = {},\n options = {\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n contentType: null,\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onComplete: function(id, xhr, isError) {\n var promise = promises[id],\n blockIdEntry = blockIdEntries[id];\n\n delete endpoints[id];\n delete promises[id];\n delete blockIdEntries[id];\n\n if (isError) {\n promise.failure();\n }\n else {\n promise.success(blockIdEntry);\n }\n }\n }));\n\n function createBlockId(partNum) {\n var digits = 5,\n zeros = new Array(digits + 1).join(\"0\"),\n paddedPartNum = (zeros + partNum).slice(-digits);\n\n return btoa(paddedPartNum);\n }\n\n qq.extend(this, {\n method: method,\n upload: function(id, xhr, sasUri, partNum, blob) {\n var promise = new qq.Promise(),\n blockId = createBlockId(partNum);\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block request for {} = part {}\", id, partNum));\n\n endpoints[id] = qq.format(\"{}&comp=block&blockid={}\", sasUri, encodeURIComponent(blockId));\n blockIdEntries[id] = {part: partNum, id: blockId};\n\n requester.initTransport(id)\n .withPayload(blob)\n .send(xhr);\n\n return promise;\n }\n });\n};\n","/* globals qq */\n/**\n * Implements the Put Block List Azure REST API call. http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx.\n */\nqq.azure.PutBlockList = function(o) {\n \"use strict\";\n\n var requester,\n method = \"PUT\",\n promises = {},\n options = {\n getBlobMetadata: function(id) {},\n log: function(str, level) {}\n },\n endpoints = {},\n endpointHandler = {\n get: function(id) {\n return endpoints[id];\n }\n };\n\n qq.extend(options, o);\n\n requester = qq.extend(this, new qq.AjaxRequester({\n validMethods: [method],\n method: method,\n successfulResponseCodes: (function() {\n var codes = {};\n codes[method] = [201];\n return codes;\n }()),\n customHeaders: function(id) {\n var params = options.getBlobMetadata(id);\n\n return qq.azure.util.getParamsAsHeaders(params);\n },\n contentType: \"text/plain\",\n endpointStore: endpointHandler,\n allowXRequestedWithAndCacheControl: false,\n cors: {\n expected: true\n },\n log: options.log,\n onSend: function() {},\n onComplete: function(id, xhr, isError) {\n var promise = promises[id];\n\n delete endpoints[id];\n delete promises[id];\n\n if (isError) {\n promise.failure(xhr);\n }\n else {\n promise.success(xhr);\n }\n\n }\n }));\n\n function createRequestBody(blockIdEntries) {\n var doc = document.implementation.createDocument(null, \"BlockList\", null);\n\n // If we don't sort the block ID entries by part number, the file will be combined incorrectly by Azure\n blockIdEntries.sort(function(a, b) {\n return a.part - b.part;\n });\n\n // Construct an XML document for each pair of etag/part values that correspond to part uploads.\n qq.each(blockIdEntries, function(idx, blockIdEntry) {\n var latestEl = doc.createElement(\"Latest\"),\n latestTextEl = doc.createTextNode(blockIdEntry.id);\n\n latestEl.appendChild(latestTextEl);\n qq(doc).children()[0].appendChild(latestEl);\n });\n\n // Turn the resulting XML document into a string fit for transport.\n return new XMLSerializer().serializeToString(doc);\n }\n\n qq.extend(this, {\n method: method,\n send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) {\n var promise = new qq.Promise(),\n blockIdsXml = createRequestBody(blockIdEntries),\n xhr;\n\n promises[id] = promise;\n\n options.log(qq.format(\"Submitting Put Block List request for {}\", id));\n\n endpoints[id] = qq.format(\"{}&comp=blocklist\", sasUri);\n\n xhr = requester.initTransport(id)\n .withPayload(blockIdsXml)\n .withHeaders({\"x-ms-blob-content-type\": fileMimeType})\n .send();\n registerXhrCallback(xhr);\n\n return promise;\n }\n });\n};\n","/*globals qq, document, CustomEvent*/\nqq.DragAndDrop = function(o) {\n \"use strict\";\n\n var options,\n HIDE_ZONES_EVENT_NAME = \"qq-hidezones\",\n HIDE_BEFORE_ENTER_ATTR = \"qq-hide-dropzone\",\n uploadDropZones = [],\n droppedFiles = [],\n disposeSupport = new qq.DisposeSupport();\n\n options = {\n dropZoneElements: [],\n allowMultipleItems: true,\n classes: {\n dropActive: null\n },\n callbacks: new qq.DragAndDrop.callbacks()\n };\n\n qq.extend(options, o, true);\n\n function uploadDroppedFiles(files, uploadDropZone) {\n // We need to convert the `FileList` to an actual `Array` to avoid iteration issues\n var filesAsArray = Array.prototype.slice.call(files);\n\n options.callbacks.dropLog(\"Grabbed \" + files.length + \" dropped files.\");\n uploadDropZone.dropDisabled(false);\n options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());\n }\n\n function traverseFileTree(entry) {\n var parseEntryPromise = new qq.Promise();\n\n if (entry.isFile) {\n entry.file(function(file) {\n var name = entry.name,\n fullPath = entry.fullPath,\n indexOfNameInFullPath = fullPath.indexOf(name);\n\n // remove file name from full path string\n fullPath = fullPath.substr(0, indexOfNameInFullPath);\n\n // remove leading slash in full path string\n if (fullPath.charAt(0) === \"/\") {\n fullPath = fullPath.substr(1);\n }\n\n file.qqPath = fullPath;\n droppedFiles.push(file);\n parseEntryPromise.success();\n },\n function(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n });\n }\n else if (entry.isDirectory) {\n getFilesInDirectory(entry).then(\n function allEntriesRead(entries) {\n var entriesLeft = entries.length;\n\n qq.each(entries, function(idx, entry) {\n traverseFileTree(entry).done(function() {\n entriesLeft -= 1;\n\n if (entriesLeft === 0) {\n parseEntryPromise.success();\n }\n });\n });\n\n if (!entries.length) {\n parseEntryPromise.success();\n }\n },\n\n function readFailure(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n }\n );\n }\n\n return parseEntryPromise;\n }\n\n // Promissory. Guaranteed to read all files in the root of the passed directory.\n function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {\n var promise = existingPromise || new qq.Promise(),\n dirReader = reader || entry.createReader();\n\n dirReader.readEntries(\n function readSuccess(entries) {\n var newEntries = accumEntries ? accumEntries.concat(entries) : entries;\n\n if (entries.length) {\n setTimeout(function() { // prevent stack overflow, however unlikely\n getFilesInDirectory(entry, dirReader, newEntries, promise);\n }, 0);\n }\n else {\n promise.success(newEntries);\n }\n },\n\n promise.failure\n );\n\n return promise;\n }\n\n function handleDataTransfer(dataTransfer, uploadDropZone) {\n var pendingFolderPromises = [],\n handleDataTransferPromise = new qq.Promise();\n\n options.callbacks.processingDroppedFiles();\n uploadDropZone.dropDisabled(true);\n\n if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.firefox()) {\n return !e.relatedTarget;\n }\n\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n e.preventDefault();\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n // dt.types.contains check is for firefox\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains(\"Files\")));\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n};\n","/*globals qq */\n/**\n * Defines the public API for FineUploader mode.\n */\n(function() {\n \"use strict\";\n\n qq.uiPublicApi = {\n addInitialFiles: function(cannedFileList) {\n this._parent.prototype.addInitialFiles.apply(this, arguments);\n this._templating.addCacheToDom();\n },\n\n clearStoredFiles: function() {\n this._parent.prototype.clearStoredFiles.apply(this, arguments);\n this._templating.clearFiles();\n },\n\n addExtraDropzone: function(element) {\n this._dnd && this._dnd.setupExtraDropzone(element);\n },\n\n removeExtraDropzone: function(element) {\n if (this._dnd) {\n return this._dnd.removeDropzone(element);\n }\n },\n\n getItemByFileId: function(id) {\n if (!this._templating.isHiddenForever(id)) {\n return this._templating.getFileContainer(id);\n }\n },\n\n reset: function() {\n this._parent.prototype.reset.apply(this, arguments);\n this._templating.reset();\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n if (this._dnd) {\n this._dnd.dispose();\n this._dnd = this._setupDragAndDrop();\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n\n this._setupClickAndEditEventHandlers();\n },\n\n setName: function(id, newName) {\n var formattedFilename = this._options.formatFileName(newName);\n\n this._parent.prototype.setName.apply(this, arguments);\n this._templating.updateFilename(id, formattedFilename);\n },\n\n pauseUpload: function(id) {\n var paused = this._parent.prototype.pauseUpload.apply(this, arguments);\n\n paused && this._templating.uploadPaused(id);\n return paused;\n },\n\n continueUpload: function(id) {\n var continued = this._parent.prototype.continueUpload.apply(this, arguments);\n\n continued && this._templating.uploadContinued(id);\n return continued;\n },\n\n getId: function(fileContainerOrChildEl) {\n return this._templating.getFileId(fileContainerOrChildEl);\n },\n\n getDropTarget: function(fileId) {\n var file = this.getFile(fileId);\n\n return file.qqDropTarget;\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploader mode.\n */\n qq.uiPrivateApi = {\n _getButton: function(buttonId) {\n var button = this._parent.prototype._getButton.apply(this, arguments);\n\n if (!button) {\n if (buttonId === this._defaultButtonId) {\n button = this._templating.getButton();\n }\n }\n\n return button;\n },\n\n _removeFileItem: function(fileId) {\n this._templating.removeFile(fileId);\n },\n\n _setupClickAndEditEventHandlers: function() {\n this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();\n\n // A better approach would be to check specifically for focusin event support by querying the DOM API,\n // but the DOMFocusIn event is not exposed as a property, so we have to resort to UA string sniffing.\n this._focusinEventSupported = !qq.firefox();\n\n if (this._isEditFilenameEnabled())\n {\n this._filenameClickHandler = this._bindFilenameClickEvent();\n this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();\n this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();\n }\n },\n\n _setupDragAndDrop: function() {\n var self = this,\n dropZoneElements = this._options.dragAndDrop.extraDropzones,\n templating = this._templating,\n defaultDropZone = templating.getDropZone();\n\n defaultDropZone && dropZoneElements.push(defaultDropZone);\n\n return new qq.DragAndDrop({\n dropZoneElements: dropZoneElements,\n allowMultipleItems: this._options.multiple,\n classes: {\n dropActive: this._options.classes.dropActive\n },\n callbacks: {\n processingDroppedFiles: function() {\n templating.showDropProcessing();\n },\n processingDroppedFilesComplete: function(files, targetEl) {\n templating.hideDropProcessing();\n\n qq.each(files, function(idx, file) {\n file.qqDropTarget = targetEl;\n });\n\n if (files.length) {\n self.addFiles(files, null, null);\n }\n },\n dropError: function(code, errorData) {\n self._itemError(code, errorData);\n },\n dropLog: function(message, level) {\n self.log(message, level);\n }\n }\n });\n },\n\n _bindFileButtonsClickEvent: function() {\n var self = this;\n\n return new qq.FileButtonsClickHandler({\n templating: this._templating,\n\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n\n onDeleteFile: function(fileId) {\n self.deleteFile(fileId);\n },\n\n onCancel: function(fileId) {\n self.cancel(fileId);\n },\n\n onRetry: function(fileId) {\n self.retry(fileId);\n },\n\n onPause: function(fileId) {\n self.pauseUpload(fileId);\n },\n\n onContinue: function(fileId) {\n self.continueUpload(fileId);\n },\n\n onGetName: function(fileId) {\n return self.getName(fileId);\n }\n });\n },\n\n _isEditFilenameEnabled: function() {\n /*jshint -W014 */\n return this._templating.isEditFilenamePossible()\n && !this._options.autoUpload\n && qq.FilenameClickHandler\n && qq.FilenameInputFocusHandler\n && qq.FilenameInputFocusHandler;\n },\n\n _filenameEditHandler: function() {\n var self = this,\n templating = this._templating;\n\n return {\n templating: templating,\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n onGetUploadStatus: function(fileId) {\n return self.getUploads({id: fileId}).status;\n },\n onGetName: function(fileId) {\n return self.getName(fileId);\n },\n onSetName: function(id, newName) {\n self.setName(id, newName);\n },\n onEditingStatusChange: function(id, isEditing) {\n var qqInput = qq(templating.getEditInput(id)),\n qqFileContainer = qq(templating.getFileContainer(id));\n\n if (isEditing) {\n qqInput.addClass(\"qq-editing\");\n templating.hideFilename(id);\n templating.hideEditIcon(id);\n }\n else {\n qqInput.removeClass(\"qq-editing\");\n templating.showFilename(id);\n templating.showEditIcon(id);\n }\n\n // Force IE8 and older to repaint\n qqFileContainer.addClass(\"qq-temp\").removeClass(\"qq-temp\");\n }\n };\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n this._parent.prototype._onUploadStatusChange.apply(this, arguments);\n\n if (this._isEditFilenameEnabled()) {\n // Status for a file exists before it has been added to the DOM, so we must be careful here.\n if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {\n this._templating.markFilenameEditable(id);\n this._templating.hideEditIcon(id);\n }\n }\n\n if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {\n this._templating.hideRetry(id);\n this._templating.setStatusText(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);\n }\n else if (newStatus === qq.status.UPLOAD_FAILED) {\n this._templating.hidePause(id);\n }\n },\n\n _bindFilenameInputFocusInEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusInHandler(spec);\n },\n\n _bindFilenameInputFocusEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusHandler(spec);\n },\n\n _bindFilenameClickEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameClickHandler(spec);\n },\n\n _storeForLater: function(id) {\n this._parent.prototype._storeForLater.apply(this, arguments);\n this._templating.hideSpinner(id);\n },\n\n _onAllComplete: function(successful, failed) {\n this._parent.prototype._onAllComplete.apply(this, arguments);\n this._templating.resetTotalProgress();\n },\n\n _onSubmit: function(id, name) {\n var file = this.getFile(id);\n\n if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {\n this._paramsStore.addReadOnly(id, {\n qqpath: file.qqPath\n });\n }\n\n this._parent.prototype._onSubmit.apply(this, arguments);\n this._addToList(id, name);\n },\n\n // The file item has been added to the DOM.\n _onSubmitted: function(id) {\n // If the edit filename feature is enabled, mark the filename element as \"editable\" and the associated edit icon\n if (this._isEditFilenameEnabled()) {\n this._templating.markFilenameEditable(id);\n this._templating.showEditIcon(id);\n\n // If the focusin event is not supported, we must add a focus handler to the newly create edit filename text input\n if (!this._focusinEventSupported) {\n this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));\n }\n }\n },\n\n // Update the progress bar & percentage as the file is uploaded\n _onProgress: function(id, name, loaded, total) {\n this._parent.prototype._onProgress.apply(this, arguments);\n\n this._templating.updateProgress(id, loaded, total);\n\n if (total === 0 || Math.round(loaded / total * 100) === 100) {\n this._templating.hideCancel(id);\n this._templating.hidePause(id);\n this._templating.hideProgress(id);\n this._templating.setStatusText(id, this._options.text.waitingForResponse);\n\n // If ~last byte was sent, display total file size\n this._displayFileSize(id);\n }\n else {\n // If still uploading, display percentage - total size is actually the total request(s) size\n this._displayFileSize(id, loaded, total);\n }\n },\n\n _onTotalProgress: function(loaded, total) {\n this._parent.prototype._onTotalProgress.apply(this, arguments);\n this._templating.updateTotalProgress(loaded, total);\n },\n\n _onComplete: function(id, name, result, xhr) {\n var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments),\n templating = this._templating,\n fileContainer = templating.getFileContainer(id),\n self = this;\n\n function completeUpload(result) {\n // If this file is not represented in the templating module, perhaps it was hidden intentionally.\n // If so, don't perform any UI-related tasks related to this file.\n if (!fileContainer) {\n return;\n }\n\n templating.setStatusText(id);\n\n qq(fileContainer).removeClass(self._classes.retrying);\n templating.hideProgress(id);\n\n if (self.getUploads({id: id}).status !== qq.status.UPLOAD_FAILED) {\n templating.hideCancel(id);\n }\n templating.hideSpinner(id);\n\n if (result.success) {\n self._markFileAsSuccessful(id);\n }\n else {\n qq(fileContainer).addClass(self._classes.fail);\n templating.showCancel(id);\n\n if (templating.isRetryPossible() && !self._preventRetries[id]) {\n qq(fileContainer).addClass(self._classes.retryable);\n templating.showRetry(id);\n }\n self._controlFailureTextDisplay(id, result);\n }\n }\n\n // The parent may need to perform some async operation before we can accurately determine the status of the upload.\n if (parentRetVal instanceof qq.Promise) {\n parentRetVal.done(function(newResult) {\n completeUpload(newResult);\n });\n\n }\n else {\n completeUpload(result);\n }\n\n return parentRetVal;\n },\n\n _markFileAsSuccessful: function(id) {\n var templating = this._templating;\n\n if (this._isDeletePossible()) {\n templating.showDeleteButton(id);\n }\n\n qq(templating.getFileContainer(id)).addClass(this._classes.success);\n\n this._maybeUpdateThumbnail(id);\n },\n\n _onUploadPrep: function(id) {\n this._parent.prototype._onUploadPrep.apply(this, arguments);\n this._templating.showSpinner(id);\n },\n\n _onUpload: function(id, name) {\n var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);\n\n this._templating.showSpinner(id);\n\n return parentRetVal;\n },\n\n _onUploadChunk: function(id, chunkData) {\n this._parent.prototype._onUploadChunk.apply(this, arguments);\n\n // Only display the pause button if we have finished uploading at least one chunk\n // & this file can be resumed\n if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {\n this._templating.allowPause(id);\n }\n },\n\n _onCancel: function(id, name) {\n this._parent.prototype._onCancel.apply(this, arguments);\n this._removeFileItem(id);\n\n if (this._getNotFinished() === 0) {\n this._templating.resetTotalProgress();\n }\n },\n\n _onBeforeAutoRetry: function(id) {\n var retryNumForDisplay, maxAuto, retryNote;\n\n this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);\n\n this._showCancelLink(id);\n\n if (this._options.retry.showAutoRetryNote) {\n retryNumForDisplay = this._autoRetries[id];\n maxAuto = this._options.retry.maxAutoAttempts;\n\n retryNote = this._options.retry.autoRetryNote.replace(/\\{retryNum\\}/g, retryNumForDisplay);\n retryNote = retryNote.replace(/\\{maxAuto\\}/g, maxAuto);\n\n this._templating.setStatusText(id, retryNote);\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);\n }\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {\n this._templating.resetProgress(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);\n this._templating.setStatusText(id);\n this._templating.showSpinner(id);\n this._showCancelLink(id);\n return true;\n }\n else {\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);\n this._templating.showRetry(id);\n return false;\n }\n },\n\n _onSubmitDelete: function(id) {\n var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);\n\n this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);\n },\n\n _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {\n if (this._options.deleteFile.forceConfirm) {\n this._showDeleteConfirm.apply(this, arguments);\n }\n else {\n this._sendDeleteRequest.apply(this, arguments);\n }\n },\n\n _onDeleteComplete: function(id, xhr, isError) {\n this._parent.prototype._onDeleteComplete.apply(this, arguments);\n\n this._templating.hideSpinner(id);\n\n if (isError) {\n this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);\n this._templating.showDeleteButton(id);\n }\n else {\n this._removeFileItem(id);\n }\n },\n\n _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {\n this._templating.hideDeleteButton(id);\n this._templating.showSpinner(id);\n this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);\n this._deleteHandler.sendDelete.apply(this, arguments);\n },\n\n _showDeleteConfirm: function(id, uuid, mandatedParams) {\n /*jshint -W004 */\n var fileName = this.getName(id),\n confirmMessage = this._options.deleteFile.confirmMessage.replace(/\\{filename\\}/g, fileName),\n uuid = this.getUuid(id),\n deleteRequestArgs = arguments,\n self = this,\n retVal;\n\n retVal = this._options.showConfirm(confirmMessage);\n\n if (qq.isGenericPromise(retVal)) {\n retVal.then(function() {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n });\n }\n else if (retVal !== false) {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n }\n },\n\n _addToList: function(id, name, canned) {\n var prependData,\n prependIndex = 0,\n dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled,\n record;\n\n if (this._options.display.prependFiles) {\n if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {\n prependIndex = this._filesInBatchAddedToUi - 1;\n }\n\n prependData = {\n index: prependIndex\n };\n }\n\n if (!canned) {\n if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {\n this._templating.disableCancel();\n }\n\n // Cancel all existing (previous) files and clear the list if this file is not part of\n // a scaled file group that has already been accepted, or if this file is not part of\n // a scaled file group at all.\n if (!this._options.multiple) {\n record = this.getUploads({id: id});\n\n this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;\n\n if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {\n this._handler.cancelAll();\n this._clearList();\n this._handledProxyGroup = null;\n }\n }\n }\n\n if (canned) {\n this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);\n }\n else {\n this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);\n }\n\n this._filesInBatchAddedToUi += 1;\n\n if (canned ||\n (this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading)) {\n\n this._displayFileSize(id);\n }\n },\n\n _clearList: function() {\n this._templating.clearFiles();\n this.clearStoredFiles();\n },\n\n _displayFileSize: function(id, loadedSize, totalSize) {\n var size = this.getSize(id),\n sizeForDisplay = this._formatSize(size);\n\n if (size >= 0) {\n if (loadedSize !== undefined && totalSize !== undefined) {\n sizeForDisplay = this._formatProgress(loadedSize, totalSize);\n }\n\n this._templating.updateSize(id, sizeForDisplay);\n }\n },\n\n _formatProgress: function(uploadedSize, totalSize) {\n var message = this._options.text.formatProgress;\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n r(\"{percent}\", Math.round(uploadedSize / totalSize * 100));\n r(\"{total_size}\", this._formatSize(totalSize));\n return message;\n },\n\n _controlFailureTextDisplay: function(id, response) {\n var mode, responseProperty, failureReason;\n\n mode = this._options.failedUploadTextDisplay.mode;\n responseProperty = this._options.failedUploadTextDisplay.responseProperty;\n\n if (mode === \"custom\") {\n failureReason = response[responseProperty];\n if (!failureReason) {\n failureReason = this._options.text.failUpload;\n }\n\n this._templating.setStatusText(id, failureReason);\n\n if (this._options.failedUploadTextDisplay.enableTooltip) {\n this._showTooltip(id, failureReason);\n }\n }\n else if (mode === \"default\") {\n this._templating.setStatusText(id, this._options.text.failUpload);\n }\n else if (mode !== \"none\") {\n this.log(\"failedUploadTextDisplay.mode value of '\" + mode + \"' is not valid\", \"warn\");\n }\n },\n\n _showTooltip: function(id, text) {\n this._templating.getFileContainer(id).title = text;\n },\n\n _showCancelLink: function(id) {\n if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {\n this._templating.showCancel(id);\n }\n },\n\n _itemError: function(code, name, item) {\n var message = this._parent.prototype._itemError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _batchError: function(message) {\n this._parent.prototype._batchError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _setupPastePrompt: function() {\n var self = this;\n\n this._options.callbacks.onPasteReceived = function() {\n var message = self._options.paste.namePromptMessage,\n defaultVal = self._options.paste.defaultName;\n\n return self._options.showPrompt(message, defaultVal);\n };\n },\n\n _fileOrBlobRejected: function(id, name) {\n this._totalFilesInBatch -= 1;\n this._parent.prototype._fileOrBlobRejected.apply(this, arguments);\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n this._totalFilesInBatch = items.length;\n this._filesInBatchAddedToUi = 0;\n this._parent.prototype._prepareItemsForUpload.apply(this, arguments);\n },\n\n _maybeUpdateThumbnail: function(fileId) {\n var thumbnailUrl = this._thumbnailUrls[fileId],\n fileStatus = this.getUploads({id: fileId}).status;\n\n if (fileStatus !== qq.status.DELETED &&\n (thumbnailUrl ||\n this._options.thumbnails.placeholders.waitUntilResponse ||\n !qq.supportedFeatures.imagePreviews)) {\n\n // This will replace the \"waiting\" placeholder with a \"preview not available\" placeholder\n // if called with a null thumbnailUrl.\n this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id = this._parent.prototype._addCannedFile.apply(this, arguments);\n\n this._addToList(id, this.getName(id), true);\n this._templating.hideSpinner(id);\n this._templating.hideCancel(id);\n this._markFileAsSuccessful(id);\n\n return id;\n },\n\n _setSize: function(id, newSize) {\n this._parent.prototype._setSize.apply(this, arguments);\n\n this._templating.updateSize(id, this._formatSize(newSize));\n },\n\n _sessionRequestComplete: function() {\n this._templating.addCacheToDom();\n this._parent.prototype._sessionRequestComplete.apply(this, arguments);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploader mode, which is a default UI w/ drag & drop uploading.\n */\nqq.FineUploader = function(o, namespace) {\n \"use strict\";\n\n var self = this;\n\n // By default this should inherit instance data from FineUploaderBasic, but this can be overridden\n // if the (internal) caller defines a different parent. The parent is also used by\n // the private and public API functions that need to delegate to a parent function.\n this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;\n this._parent.apply(this, arguments);\n\n // Options provided by FineUploader mode\n qq.extend(this._options, {\n element: null,\n\n button: null,\n\n listElement: null,\n\n dragAndDrop: {\n extraDropzones: [],\n reportDirectoryPaths: false\n },\n\n text: {\n formatProgress: \"{percent}% of {total_size}\",\n failUpload: \"Upload failed\",\n waitingForResponse: \"Processing...\",\n paused: \"Paused\"\n },\n\n template: \"qq-template\",\n\n classes: {\n retrying: \"qq-upload-retrying\",\n retryable: \"qq-upload-retryable\",\n success: \"qq-upload-success\",\n fail: \"qq-upload-fail\",\n editable: \"qq-editable\",\n hide: \"qq-hide\",\n dropActive: \"qq-upload-drop-area-active\"\n },\n\n failedUploadTextDisplay: {\n mode: \"default\", //default, custom, or none\n responseProperty: \"error\",\n enableTooltip: true\n },\n\n messages: {\n tooManyFilesError: \"You may only drop one file\",\n unsupportedBrowser: \"Unrecoverable error - this browser does not permit file uploading of any kind.\"\n },\n\n retry: {\n showAutoRetryNote: true,\n autoRetryNote: \"Retrying {retryNum}/{maxAuto}...\"\n },\n\n deleteFile: {\n forceConfirm: false,\n confirmMessage: \"Are you sure you want to delete {filename}?\",\n deletingStatusText: \"Deleting...\",\n deletingFailedText: \"Delete failed\"\n\n },\n\n display: {\n fileSizeOnSubmit: false,\n prependFiles: false\n },\n\n paste: {\n promptForName: false,\n namePromptMessage: \"Please name this image\"\n },\n\n thumbnails: {\n customResizer: null,\n maxCount: 0,\n placeholders: {\n waitUntilResponse: false,\n notAvailablePath: null,\n waitingPath: null\n },\n timeBetweenThumbs: 750\n },\n\n scaling: {\n hideScaled: false\n },\n\n showMessage: function(message) {\n if (self._templating.hasDialog(\"alert\")) {\n return self._templating.showDialog(\"alert\", message);\n }\n else {\n setTimeout(function() {\n window.alert(message);\n }, 0);\n }\n },\n\n showConfirm: function(message) {\n if (self._templating.hasDialog(\"confirm\")) {\n return self._templating.showDialog(\"confirm\", message);\n }\n else {\n return window.confirm(message);\n }\n },\n\n showPrompt: function(message, defaultValue) {\n if (self._templating.hasDialog(\"prompt\")) {\n return self._templating.showDialog(\"prompt\", message, defaultValue);\n }\n else {\n return window.prompt(message, defaultValue);\n }\n }\n }, true);\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._templating = new qq.Templating({\n log: qq.bind(this.log, this),\n templateIdOrEl: this._options.template,\n containerEl: this._options.element,\n fileContainerEl: this._options.listElement,\n button: this._options.button,\n imageGenerator: this._imageGenerator,\n classes: {\n hide: this._options.classes.hide,\n editable: this._options.classes.editable\n },\n limits: {\n maxThumbs: this._options.thumbnails.maxCount,\n timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs\n },\n placeholders: {\n waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,\n thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,\n waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath\n },\n text: this._options.text\n });\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);\n }\n else if (!qq.supportedFeatures.uploading || (this._options.cors.expected && !qq.supportedFeatures.uploadCors)) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowser);\n }\n else {\n this._wrapCallbacks();\n\n this._templating.render();\n\n this._classes = this._options.classes;\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._setupClickAndEditEventHandlers();\n\n if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {\n this._dnd = this._setupDragAndDrop();\n }\n\n if (this._options.paste.targetElement && this._options.paste.promptForName) {\n if (qq.PasteSupport) {\n this._setupPastePrompt();\n }\n else {\n this.log(\"Paste support module not found.\", \"error\");\n }\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n }\n};\n\n// Inherit the base public & private API methods\nqq.extend(qq.FineUploader.prototype, qq.basePublicApi);\nqq.extend(qq.FineUploader.prototype, qq.basePrivateApi);\n\n// Add the FineUploader/default UI public & private UI methods, which may override some base methods.\nqq.extend(qq.FineUploader.prototype, qq.uiPublicApi);\nqq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);\n","/* globals qq */\n/* jshint -W065 */\n/**\n * Module responsible for rendering all Fine Uploader UI templates. This module also asserts at least\n * a limited amount of control over the template elements after they are added to the DOM.\n * Wherever possible, this module asserts total control over template elements present in the DOM.\n *\n * @param spec Specification object used to control various templating behaviors\n * @constructor\n */\nqq.Templating = function(spec) {\n \"use strict\";\n\n var FILE_ID_ATTR = \"qq-file-id\",\n FILE_CLASS_PREFIX = \"qq-file-id-\",\n THUMBNAIL_MAX_SIZE_ATTR = \"qq-max-size\",\n THUMBNAIL_SERVER_SCALE_ATTR = \"qq-server-scale\",\n // This variable is duplicated in the DnD module since it can function as a standalone as well\n HIDE_DROPZONE_ATTR = \"qq-hide-dropzone\",\n DROPZPONE_TEXT_ATTR = \"qq-drop-area-text\",\n IN_PROGRESS_CLASS = \"qq-in-progress\",\n HIDDEN_FOREVER_CLASS = \"qq-hidden-forever\",\n fileBatch = {\n content: document.createDocumentFragment(),\n map: {}\n },\n isCancelDisabled = false,\n generatedThumbnails = 0,\n thumbnailQueueMonitorRunning = false,\n thumbGenerationQueue = [],\n thumbnailMaxSize = -1,\n options = {\n log: null,\n limits: {\n maxThumbs: 0,\n timeBetweenThumbs: 750\n },\n templateIdOrEl: \"qq-template\",\n containerEl: null,\n fileContainerEl: null,\n button: null,\n imageGenerator: null,\n classes: {\n hide: \"qq-hide\",\n editable: \"qq-editable\"\n },\n placeholders: {\n waitUntilUpdate: false,\n thumbnailNotAvailable: null,\n waitingForThumbnail: null\n },\n text: {\n paused: \"Paused\"\n }\n },\n selectorClasses = {\n button: \"qq-upload-button-selector\",\n alertDialog: \"qq-alert-dialog-selector\",\n dialogCancelButton: \"qq-cancel-button-selector\",\n confirmDialog: \"qq-confirm-dialog-selector\",\n dialogMessage: \"qq-dialog-message-selector\",\n dialogOkButton: \"qq-ok-button-selector\",\n promptDialog: \"qq-prompt-dialog-selector\",\n uploader: \"qq-uploader-selector\",\n drop: \"qq-upload-drop-area-selector\",\n list: \"qq-upload-list-selector\",\n progressBarContainer: \"qq-progress-bar-container-selector\",\n progressBar: \"qq-progress-bar-selector\",\n totalProgressBarContainer: \"qq-total-progress-bar-container-selector\",\n totalProgressBar: \"qq-total-progress-bar-selector\",\n file: \"qq-upload-file-selector\",\n spinner: \"qq-upload-spinner-selector\",\n size: \"qq-upload-size-selector\",\n cancel: \"qq-upload-cancel-selector\",\n pause: \"qq-upload-pause-selector\",\n continueButton: \"qq-upload-continue-selector\",\n deleteButton: \"qq-upload-delete-selector\",\n retry: \"qq-upload-retry-selector\",\n statusText: \"qq-upload-status-text-selector\",\n editFilenameInput: \"qq-edit-filename-selector\",\n editNameIcon: \"qq-edit-filename-icon-selector\",\n dropText: \"qq-upload-drop-area-text-selector\",\n dropProcessing: \"qq-drop-processing-selector\",\n dropProcessingSpinner: \"qq-drop-processing-spinner-selector\",\n thumbnail: \"qq-thumbnail-selector\"\n },\n previewGeneration = {},\n cachedThumbnailNotAvailableImg = new qq.Promise(),\n cachedWaitingForThumbnailImg = new qq.Promise(),\n log,\n isEditElementsExist,\n isRetryElementExist,\n templateHtml,\n container,\n fileList,\n showThumbnails,\n serverScale,\n\n // During initialization of the templating module we should cache any\n // placeholder images so we can quickly swap them into the file list on demand.\n // Any placeholder images that cannot be loaded/found are simply ignored.\n cacheThumbnailPlaceholders = function() {\n var notAvailableUrl = options.placeholders.thumbnailNotAvailable,\n waitingUrl = options.placeholders.waitingForThumbnail,\n spec = {\n maxSize: thumbnailMaxSize,\n scale: serverScale\n };\n\n if (showThumbnails) {\n if (notAvailableUrl) {\n options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedThumbnailNotAvailableImg.success(updatedImg);\n },\n function() {\n cachedThumbnailNotAvailableImg.failure();\n log(\"Problem loading 'not available' placeholder image at \" + notAvailableUrl, \"error\");\n }\n );\n }\n else {\n cachedThumbnailNotAvailableImg.failure();\n }\n\n if (waitingUrl) {\n options.imageGenerator.generate(waitingUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedWaitingForThumbnailImg.success(updatedImg);\n },\n function() {\n cachedWaitingForThumbnailImg.failure();\n log(\"Problem loading 'waiting for thumbnail' placeholder image at \" + waitingUrl, \"error\");\n }\n );\n }\n else {\n cachedWaitingForThumbnailImg.failure();\n }\n }\n },\n\n // Displays a \"waiting for thumbnail\" type placeholder image\n // iff we were able to load it during initialization of the templating module.\n displayWaitingImg = function(thumbnail) {\n var waitingImgPlacement = new qq.Promise();\n\n cachedWaitingForThumbnailImg.then(function(img) {\n maybeScalePlaceholderViaCss(img, thumbnail);\n /* jshint eqnull:true */\n if (!thumbnail.src) {\n thumbnail.src = img.src;\n thumbnail.onload = function() {\n thumbnail.onload = null;\n show(thumbnail);\n waitingImgPlacement.success();\n };\n }\n else {\n waitingImgPlacement.success();\n }\n }, function() {\n // In some browsers (such as IE9 and older) an img w/out a src attribute\n // are displayed as \"broken\" images, so we should just hide the img tag\n // if we aren't going to display the \"waiting\" placeholder.\n hide(thumbnail);\n waitingImgPlacement.success();\n });\n\n return waitingImgPlacement;\n },\n\n generateNewPreview = function(id, blob, spec) {\n var thumbnail = getThumbnail(id);\n\n log(\"Generating new thumbnail for \" + id);\n blob.qqThumbnailId = id;\n\n return options.imageGenerator.generate(blob, thumbnail, spec).then(\n function() {\n generatedThumbnails++;\n show(thumbnail);\n previewGeneration[id].success();\n },\n function() {\n previewGeneration[id].failure();\n\n // Display the \"not available\" placeholder img only if we are\n // not expecting a thumbnail at a later point, such as in a server response.\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n }\n });\n },\n\n generateNextQueuedPreview = function() {\n if (thumbGenerationQueue.length) {\n thumbnailQueueMonitorRunning = true;\n\n var queuedThumbRequest = thumbGenerationQueue.shift();\n\n if (queuedThumbRequest.update) {\n processUpdateQueuedPreviewRequest(queuedThumbRequest);\n }\n else {\n processNewQueuedPreviewRequest(queuedThumbRequest);\n }\n }\n else {\n thumbnailQueueMonitorRunning = false;\n }\n },\n\n getCancel = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.cancel);\n },\n\n getContinue = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.continueButton);\n },\n\n getDialog = function(type) {\n return getTemplateEl(container, selectorClasses[type + \"Dialog\"]);\n },\n\n getDelete = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.deleteButton);\n },\n\n getDropProcessing = function() {\n return getTemplateEl(container, selectorClasses.dropProcessing);\n },\n\n getEditIcon = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editNameIcon);\n },\n\n getFile = function(id) {\n return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);\n },\n\n getFilename = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.file);\n },\n\n getPause = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.pause);\n },\n\n getProgress = function(id) {\n /* jshint eqnull:true */\n // Total progress bar\n if (id == null) {\n return getTemplateEl(container, selectorClasses.totalProgressBarContainer) ||\n getTemplateEl(container, selectorClasses.totalProgressBar);\n }\n\n // Per-file progress bar\n return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) ||\n getTemplateEl(getFile(id), selectorClasses.progressBar);\n },\n\n getRetry = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.retry);\n },\n\n getSize = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.size);\n },\n\n getSpinner = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.spinner);\n },\n\n getTemplateEl = function(context, cssClass) {\n return context && qq(context).getFirstByClass(cssClass);\n },\n\n getThumbnail = function(id) {\n return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);\n },\n\n hide = function(el) {\n el && qq(el).addClass(options.classes.hide);\n },\n\n // Ensures a placeholder image does not exceed any max size specified\n // via `style` attribute properties iff was not used to scale\n // the placeholder AND the target doesn't already have these `style` attribute properties set.\n maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {\n var maxWidth = placeholder.style.maxWidth,\n maxHeight = placeholder.style.maxHeight;\n\n if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {\n qq(thumbnail).css({\n maxWidth: maxWidth,\n maxHeight: maxHeight\n });\n }\n },\n\n // Displays a \"thumbnail not available\" type placeholder image\n // iff we were able to load this placeholder during initialization\n // of the templating module or after preview generation has failed.\n maybeSetDisplayNotAvailableImg = function(id, thumbnail) {\n var previewing = previewGeneration[id] || new qq.Promise().failure(),\n notAvailableImgPlacement = new qq.Promise();\n\n cachedThumbnailNotAvailableImg.then(function(img) {\n previewing.then(\n function() {\n notAvailableImgPlacement.success();\n },\n function() {\n maybeScalePlaceholderViaCss(img, thumbnail);\n\n thumbnail.onload = function() {\n thumbnail.onload = null;\n notAvailableImgPlacement.success();\n };\n\n thumbnail.src = img.src;\n show(thumbnail);\n }\n );\n });\n\n return notAvailableImgPlacement;\n },\n\n /**\n * Grabs the HTML from the script tag holding the template markup. This function will also adjust\n * some internally-tracked state variables based on the contents of the template.\n * The template is filtered so that irrelevant elements (such as the drop zone if DnD is not supported)\n * are omitted from the DOM. Useful errors will be thrown if the template cannot be parsed.\n *\n * @returns {{template: *, fileTemplate: *}} HTML for the top-level file items templates\n */\n parseAndGetTemplate = function() {\n var scriptEl,\n scriptHtml,\n fileListNode,\n tempTemplateEl,\n fileListHtml,\n defaultButton,\n dropArea,\n thumbnail,\n dropProcessing,\n dropTextEl,\n uploaderEl;\n\n log(\"Parsing template\");\n\n /*jshint -W116*/\n if (options.templateIdOrEl == null) {\n throw new Error(\"You MUST specify either a template element or ID!\");\n }\n\n // Grab the contents of the script tag holding the template.\n if (qq.isString(options.templateIdOrEl)) {\n scriptEl = document.getElementById(options.templateIdOrEl);\n\n if (scriptEl === null) {\n throw new Error(qq.format(\"Cannot find template script at ID '{}'!\", options.templateIdOrEl));\n }\n\n scriptHtml = scriptEl.innerHTML;\n }\n else {\n if (options.templateIdOrEl.innerHTML === undefined) {\n throw new Error(\"You have specified an invalid value for the template option! \" +\n \"It must be an ID or an Element.\");\n }\n\n scriptHtml = options.templateIdOrEl.innerHTML;\n }\n\n scriptHtml = qq.trimStr(scriptHtml);\n tempTemplateEl = document.createElement(\"div\");\n tempTemplateEl.appendChild(qq.toElement(scriptHtml));\n uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);\n\n // Don't include the default template button in the DOM\n // if an alternate button container has been specified.\n if (options.button) {\n defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);\n if (defaultButton) {\n qq(defaultButton).remove();\n }\n }\n\n // Omit the drop processing element from the DOM if DnD is not supported by the UA,\n // or the drag and drop module is not found.\n // NOTE: We are consciously not removing the drop zone if the UA doesn't support DnD\n // to support layouts where the drop zone is also a container for visible elements,\n // such as the file list.\n if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {\n dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);\n if (dropProcessing) {\n qq(dropProcessing).remove();\n }\n }\n\n dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);\n\n // If DnD is not available then remove\n // it from the DOM as well.\n if (dropArea && !qq.DragAndDrop) {\n log(\"DnD module unavailable.\", \"info\");\n qq(dropArea).remove();\n }\n\n if (!qq.supportedFeatures.fileDrop) {\n // don't display any \"drop files to upload\" background text\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {\n // If there is a drop area defined in the template, and the current UA doesn't support DnD,\n // and the drop area is marked as \"hide before enter\", ensure it is hidden as the DnD module\n // will not do this (since we will not be loading the DnD module)\n qq(dropArea).css({\n display: \"none\"\n });\n }\n }\n else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {\n dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);\n dropTextEl && qq(dropTextEl).remove();\n }\n\n // Ensure the `showThumbnails` flag is only set if the thumbnail element\n // is present in the template AND the current UA is capable of generating client-side previews.\n thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);\n if (!showThumbnails) {\n thumbnail && qq(thumbnail).remove();\n }\n else if (thumbnail) {\n thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));\n // Only enforce max size if the attr value is non-zero\n thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;\n\n serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);\n }\n showThumbnails = showThumbnails && thumbnail;\n\n isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;\n isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;\n\n fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);\n /*jshint -W116*/\n if (fileListNode == null) {\n throw new Error(\"Could not find the file list container in the template!\");\n }\n\n fileListHtml = fileListNode.innerHTML;\n fileListNode.innerHTML = \"\";\n\n // We must call `createElement` in IE8 in order to target and hide any via CSS\n if (tempTemplateEl.getElementsByTagName(\"DIALOG\").length) {\n document.createElement(\"dialog\");\n }\n\n log(\"Template parsing complete\");\n\n return {\n template: qq.trimStr(tempTemplateEl.innerHTML),\n fileTemplate: qq.trimStr(fileListHtml)\n };\n },\n\n prependFile = function(el, index, fileList) {\n var parentEl = fileList,\n beforeEl = parentEl.firstChild;\n\n if (index > 0) {\n beforeEl = qq(parentEl).children()[index].nextSibling;\n\n }\n\n parentEl.insertBefore(el, beforeEl);\n },\n\n processNewQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n optFileOrBlob = queuedThumbRequest.optFileOrBlob,\n relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n maxSize: thumbnailMaxSize,\n orient: true,\n scale: true\n };\n\n if (qq.supportedFeatures.imagePreviews) {\n if (thumbnail) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n displayWaitingImg(thumbnail).done(function() {\n previewGeneration[id] = new qq.Promise();\n\n previewGeneration[id].done(function() {\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n });\n\n /* jshint eqnull: true */\n // If we've already generated an for this file, use the one that exists,\n // don't waste resources generating a new one.\n if (relatedThumbnailId != null) {\n useCachedPreview(id, relatedThumbnailId);\n }\n else {\n generateNewPreview(id, optFileOrBlob, spec);\n }\n });\n }\n }\n // File element in template may have been removed, so move on to next item in queue\n else {\n generateNextQueuedPreview();\n }\n }\n else if (thumbnail) {\n displayWaitingImg(thumbnail);\n generateNextQueuedPreview();\n }\n },\n\n processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n thumbnailUrl = queuedThumbRequest.thumbnailUrl,\n showWaitingImg = queuedThumbRequest.showWaitingImg,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n scale: serverScale,\n maxSize: thumbnailMaxSize\n };\n\n if (thumbnail) {\n if (thumbnailUrl) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n if (showWaitingImg) {\n displayWaitingImg(thumbnail);\n }\n\n return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(\n function() {\n show(thumbnail);\n generatedThumbnails++;\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n },\n\n function() {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n }\n );\n }\n }\n else {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n }\n },\n\n setProgressBarWidth = function(id, percent) {\n var bar = getProgress(id),\n /* jshint eqnull:true */\n progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;\n\n if (bar && !qq(bar).hasClass(progressBarSelector)) {\n bar = qq(bar).getFirstByClass(progressBarSelector);\n }\n\n if (bar) {\n qq(bar).css({width: percent + \"%\"});\n bar.setAttribute(\"aria-valuenow\", percent);\n }\n },\n\n show = function(el) {\n el && qq(el).removeClass(options.classes.hide);\n },\n\n useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {\n var targetThumbnail = getThumbnail(targetThumbnailId),\n cachedThumbnail = getThumbnail(cachedThumbnailId);\n\n log(qq.format(\"ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.\", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));\n\n // Generation of the related thumbnail may still be in progress, so, wait until it is done.\n previewGeneration[cachedThumbnailId].then(function() {\n generatedThumbnails++;\n previewGeneration[targetThumbnailId].success();\n log(qq.format(\"Now using previously generated thumbnail created for ID {} on ID {}.\", cachedThumbnailId, targetThumbnailId));\n targetThumbnail.src = cachedThumbnail.src;\n show(targetThumbnail);\n },\n function() {\n previewGeneration[targetThumbnailId].failure();\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);\n }\n });\n };\n\n qq.extend(options, spec);\n log = options.log;\n\n // No need to worry about conserving CPU or memory on older browsers,\n // since there is no ability to preview, and thumbnail display is primitive and quick.\n if (!qq.supportedFeatures.imagePreviews) {\n options.limits.timeBetweenThumbs = 0;\n options.limits.maxThumbs = 0;\n }\n\n container = options.containerEl;\n showThumbnails = options.imageGenerator !== undefined;\n templateHtml = parseAndGetTemplate();\n\n cacheThumbnailPlaceholders();\n\n qq.extend(this, {\n render: function() {\n log(\"Rendering template in DOM.\");\n\n generatedThumbnails = 0;\n\n container.innerHTML = templateHtml.template;\n hide(getDropProcessing());\n this.hideTotalProgress();\n fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);\n\n log(\"Template rendering complete\");\n },\n\n renderFailure: function(message) {\n var cantRenderEl = qq.toElement(message);\n container.innerHTML = \"\";\n container.appendChild(cantRenderEl);\n },\n\n reset: function() {\n this.render();\n },\n\n clearFiles: function() {\n fileList.innerHTML = \"\";\n },\n\n disableCancel: function() {\n isCancelDisabled = true;\n },\n\n addFile: function(id, name, prependInfo, hideForever, batch) {\n var fileEl = qq.toElement(templateHtml.fileTemplate),\n fileNameEl = getTemplateEl(fileEl, selectorClasses.file),\n uploaderEl = getTemplateEl(container, selectorClasses.uploader),\n fileContainer = batch ? fileBatch.content : fileList,\n thumb;\n\n if (batch) {\n fileBatch.map[id] = fileEl;\n }\n\n qq(fileEl).addClass(FILE_CLASS_PREFIX + id);\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (fileNameEl) {\n qq(fileNameEl).setText(name);\n fileNameEl.setAttribute(\"title\", name);\n }\n\n fileEl.setAttribute(FILE_ID_ATTR, id);\n\n if (prependInfo) {\n prependFile(fileEl, prependInfo.index, fileContainer);\n }\n else {\n fileContainer.appendChild(fileEl);\n }\n\n if (hideForever) {\n fileEl.style.display = \"none\";\n qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);\n }\n else {\n hide(getProgress(id));\n hide(getSize(id));\n hide(getDelete(id));\n hide(getRetry(id));\n hide(getPause(id));\n hide(getContinue(id));\n\n if (isCancelDisabled) {\n this.hideCancel(id);\n }\n\n thumb = getThumbnail(id);\n if (thumb && !thumb.src) {\n cachedWaitingForThumbnailImg.then(function(waitingImg) {\n thumb.src = waitingImg.src;\n if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {\n qq(thumb).css({\n maxHeight: waitingImg.style.maxHeight,\n maxWidth: waitingImg.style.maxWidth\n });\n }\n\n show(thumb);\n });\n }\n }\n },\n\n addFileToCache: function(id, name, prependInfo, hideForever) {\n this.addFile(id, name, prependInfo, hideForever, true);\n },\n\n addCacheToDom: function() {\n fileList.appendChild(fileBatch.content);\n fileBatch.content = document.createDocumentFragment();\n fileBatch.map = {};\n },\n\n removeFile: function(id) {\n qq(getFile(id)).remove();\n },\n\n getFileId: function(el) {\n var currentNode = el;\n\n if (currentNode) {\n /*jshint -W116*/\n while (currentNode.getAttribute(FILE_ID_ATTR) == null) {\n currentNode = currentNode.parentNode;\n }\n\n return parseInt(currentNode.getAttribute(FILE_ID_ATTR));\n }\n },\n\n getFileList: function() {\n return fileList;\n },\n\n markFilenameEditable: function(id) {\n var filename = getFilename(id);\n\n filename && qq(filename).addClass(options.classes.editable);\n },\n\n updateFilename: function(id, name) {\n var filenameEl = getFilename(id);\n\n if (filenameEl) {\n qq(filenameEl).setText(name);\n filenameEl.setAttribute(\"title\", name);\n }\n },\n\n hideFilename: function(id) {\n hide(getFilename(id));\n },\n\n showFilename: function(id) {\n show(getFilename(id));\n },\n\n isFileName: function(el) {\n return qq(el).hasClass(selectorClasses.file);\n },\n\n getButton: function() {\n return options.button || getTemplateEl(container, selectorClasses.button);\n },\n\n hideDropProcessing: function() {\n hide(getDropProcessing());\n },\n\n showDropProcessing: function() {\n show(getDropProcessing());\n },\n\n getDropZone: function() {\n return getTemplateEl(container, selectorClasses.drop);\n },\n\n isEditFilenamePossible: function() {\n return isEditElementsExist;\n },\n\n hideRetry: function(id) {\n hide(getRetry(id));\n },\n\n isRetryPossible: function() {\n return isRetryElementExist;\n },\n\n showRetry: function(id) {\n show(getRetry(id));\n },\n\n getFileContainer: function(id) {\n return getFile(id);\n },\n\n showEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).addClass(options.classes.editable);\n },\n\n isHiddenForever: function(id) {\n return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);\n },\n\n hideEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).removeClass(options.classes.editable);\n },\n\n isEditIcon: function(el) {\n return qq(el).hasClass(selectorClasses.editNameIcon, true);\n },\n\n getEditInput: function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);\n },\n\n isEditInput: function(el) {\n return qq(el).hasClass(selectorClasses.editFilenameInput, true);\n },\n\n updateProgress: function(id, loaded, total) {\n var bar = getProgress(id),\n percent;\n\n if (bar && total > 0) {\n percent = Math.round(loaded / total * 100);\n\n if (percent === 100) {\n hide(bar);\n }\n else {\n show(bar);\n }\n\n setProgressBarWidth(id, percent);\n }\n },\n\n updateTotalProgress: function(loaded, total) {\n this.updateProgress(null, loaded, total);\n },\n\n hideProgress: function(id) {\n var bar = getProgress(id);\n\n bar && hide(bar);\n },\n\n hideTotalProgress: function() {\n this.hideProgress();\n },\n\n resetProgress: function(id) {\n setProgressBarWidth(id, 0);\n this.hideTotalProgress(id);\n },\n\n resetTotalProgress: function() {\n this.resetProgress();\n },\n\n showCancel: function(id) {\n if (!isCancelDisabled) {\n var cancel = getCancel(id);\n\n cancel && qq(cancel).removeClass(options.classes.hide);\n }\n },\n\n hideCancel: function(id) {\n hide(getCancel(id));\n },\n\n isCancel: function(el) {\n return qq(el).hasClass(selectorClasses.cancel, true);\n },\n\n allowPause: function(id) {\n show(getPause(id));\n hide(getContinue(id));\n },\n\n uploadPaused: function(id) {\n this.setStatusText(id, options.text.paused);\n this.allowContinueButton(id);\n hide(getSpinner(id));\n },\n\n hidePause: function(id) {\n hide(getPause(id));\n },\n\n isPause: function(el) {\n return qq(el).hasClass(selectorClasses.pause, true);\n },\n\n isContinueButton: function(el) {\n return qq(el).hasClass(selectorClasses.continueButton, true);\n },\n\n allowContinueButton: function(id) {\n show(getContinue(id));\n hide(getPause(id));\n },\n\n uploadContinued: function(id) {\n this.setStatusText(id, \"\");\n this.allowPause(id);\n show(getSpinner(id));\n },\n\n showDeleteButton: function(id) {\n show(getDelete(id));\n },\n\n hideDeleteButton: function(id) {\n hide(getDelete(id));\n },\n\n isDeleteButton: function(el) {\n return qq(el).hasClass(selectorClasses.deleteButton, true);\n },\n\n isRetry: function(el) {\n return qq(el).hasClass(selectorClasses.retry, true);\n },\n\n updateSize: function(id, text) {\n var size = getSize(id);\n\n if (size) {\n show(size);\n qq(size).setText(text);\n }\n },\n\n setStatusText: function(id, text) {\n var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);\n\n if (textEl) {\n /*jshint -W116*/\n if (text == null) {\n qq(textEl).clearText();\n }\n else {\n qq(textEl).setText(text);\n }\n }\n },\n\n hideSpinner: function(id) {\n qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);\n hide(getSpinner(id));\n },\n\n showSpinner: function(id) {\n qq(getFile(id)).addClass(IN_PROGRESS_CLASS);\n show(getSpinner(id));\n },\n\n generatePreview: function(id, optFileOrBlob, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({id: id, customResizeFunction: customResizeFunction, optFileOrBlob: optFileOrBlob});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({customResizeFunction: customResizeFunction, update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n hasDialog: function(type) {\n return qq.supportedFeatures.dialogElement && !!getDialog(type);\n },\n\n showDialog: function(type, message, defaultValue) {\n var dialog = getDialog(type),\n messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage),\n inputEl = dialog.getElementsByTagName(\"INPUT\")[0],\n cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton),\n okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton),\n promise = new qq.Promise(),\n\n closeHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.removeEventListener(\"click\", okClickHandler);\n promise.failure();\n },\n\n cancelClickHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n dialog.close();\n },\n\n okClickHandler = function() {\n dialog.removeEventListener(\"close\", closeHandler);\n okBtn.removeEventListener(\"click\", okClickHandler);\n dialog.close();\n\n promise.success(inputEl && inputEl.value);\n };\n\n dialog.addEventListener(\"close\", closeHandler);\n cancelBtn.addEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.addEventListener(\"click\", okClickHandler);\n\n if (inputEl) {\n inputEl.value = defaultValue;\n }\n messageEl.textContent = message;\n\n dialog.showModal();\n\n return promise;\n }\n });\n};\n","/*globals qq */\n// Base handler for UI (FineUploader mode) events.\n// Some more specific handlers inherit from this one.\nqq.UiEventHandler = function(s, protectedApi) {\n \"use strict\";\n\n var disposer = new qq.DisposeSupport(),\n spec = {\n eventType: \"click\",\n attachTo: null,\n onHandled: function(target, event) {}\n };\n\n // This makes up the \"public\" API methods that will be accessible\n // to instances constructing a base or child handler\n qq.extend(this, {\n addHandler: function(element) {\n addHandler(element);\n },\n\n dispose: function() {\n disposer.dispose();\n }\n });\n\n function addHandler(element) {\n disposer.attach(element, spec.eventType, function(event) {\n // Only in IE: the `event` is a property of the `window`.\n event = event || window.event;\n\n // On older browsers, we must check the `srcElement` instead of the `target`.\n var target = event.target || event.srcElement;\n\n spec.onHandled(target, event);\n });\n }\n\n // These make up the \"protected\" API methods that children of this base handler will utilize.\n qq.extend(protectedApi, {\n getFileIdFromItem: function(item) {\n return item.qqFileId;\n },\n\n getDisposeSupport: function() {\n return disposer;\n }\n });\n\n qq.extend(spec, s);\n\n if (spec.attachTo) {\n addHandler(spec.attachTo);\n }\n};\n","/* global qq */\nqq.FileButtonsClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n onDeleteFile: function(fileId) {},\n onCancel: function(fileId) {},\n onRetry: function(fileId) {},\n onPause: function(fileId) {},\n onContinue: function(fileId) {},\n onGetName: function(fileId) {}\n },\n buttonHandlers = {\n cancel: function(id) { spec.onCancel(id); },\n retry: function(id) { spec.onRetry(id); },\n deleteButton: function(id) { spec.onDeleteFile(id); },\n pause: function(id) { spec.onPause(id); },\n continueButton: function(id) { spec.onContinue(id); }\n };\n\n function examineEvent(target, event) {\n qq.each(buttonHandlers, function(buttonType, handler) {\n var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1),\n fileId;\n\n if (spec.templating[\"is\" + firstLetterCapButtonType](target)) {\n fileId = spec.templating.getFileId(target);\n qq.preventDefault(event);\n spec.log(qq.format(\"Detected valid file button click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n handler(fileId);\n return false;\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect click events on filename display elements.\nqq.FilenameClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n classes: {\n file: \"qq-upload-file\",\n editNameIcon: \"qq-edit-filename-icon\"\n },\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {}\n };\n\n qq.extend(spec, s);\n\n // This will be called by the parent handler when a `click` event is received on the list element.\n function examineEvent(target, event) {\n if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n // We only allow users to change filenames of files that have been submitted but not yet uploaded.\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n qq.preventDefault(event);\n\n inheritedInternalApi.handleFilenameEdit(fileId, target, true);\n }\n }\n }\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect focusin events on file edit input elements.\nqq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n onGetUploadStatus: function(fileId) {},\n log: function(message, lvl) {}\n };\n\n if (!inheritedInternalApi) {\n inheritedInternalApi = {};\n }\n\n // This will be called by the parent handler when a `focusin` event is received on the list element.\n function handleInputFocus(target, event) {\n if (spec.templating.isEditInput(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename input focus event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n inheritedInternalApi.handleFilenameEdit(fileId, target);\n }\n }\n }\n\n spec.eventType = \"focusin\";\n spec.onHandled = handleInputFocus;\n\n qq.extend(spec, s);\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n/**\n * Child of FilenameInputFocusInHandler. Used to detect focus events on file edit input elements. This child module is only\n * needed for UAs that do not support the focusin event. Currently, only Firefox lacks this event.\n *\n * @param spec Overrides for default specifications\n */\nqq.FilenameInputFocusHandler = function(spec) {\n \"use strict\";\n\n spec.eventType = \"focus\";\n spec.attachTo = null;\n\n qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));\n};\n","/*globals qq */\n// Handles edit-related events on a file item (FineUploader mode). This is meant to be a parent handler.\n// Children will delegate to this handler when specific edit-related actions are detected.\nqq.FilenameEditHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n log: function(message, lvl) {},\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {},\n onSetName: function(fileId, newName) {},\n onEditingStatusChange: function(fileId, isEditing) {}\n };\n\n function getFilenameSansExtension(fileId) {\n var filenameSansExt = spec.onGetName(fileId),\n extIdx = filenameSansExt.lastIndexOf(\".\");\n\n if (extIdx > 0) {\n filenameSansExt = filenameSansExt.substr(0, extIdx);\n }\n\n return filenameSansExt;\n }\n\n function getOriginalExtension(fileId) {\n var origName = spec.onGetName(fileId);\n return qq.getExtension(origName);\n }\n\n // Callback iff the name has been changed\n function handleNameUpdate(newFilenameInputEl, fileId) {\n var newName = newFilenameInputEl.value,\n origExtension;\n\n if (newName !== undefined && qq.trimStr(newName).length > 0) {\n origExtension = getOriginalExtension(fileId);\n\n if (origExtension !== undefined) {\n newName = newName + \".\" + origExtension;\n }\n\n spec.onSetName(fileId, newName);\n }\n\n spec.onEditingStatusChange(fileId, false);\n }\n\n // The name has been updated if the filename edit input loses focus.\n function registerInputBlurHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"blur\", function() {\n handleNameUpdate(inputEl, fileId);\n });\n }\n\n // The name has been updated if the user presses enter.\n function registerInputEnterKeyHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"keyup\", function(event) {\n\n var code = event.keyCode || event.which;\n\n if (code === 13) {\n handleNameUpdate(inputEl, fileId);\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n\n qq.extend(inheritedInternalApi, {\n handleFilenameEdit: function(id, target, focusInput) {\n var newFilenameInputEl = spec.templating.getEditInput(id);\n\n spec.onEditingStatusChange(id, true);\n\n newFilenameInputEl.value = getFilenameSansExtension(id);\n\n if (focusInput) {\n newFilenameInputEl.focus();\n }\n\n registerInputBlurHandler(newFilenameInputEl, id);\n registerInputEnterKeyHandler(newFilenameInputEl, id);\n }\n });\n};\n","/*globals qq */\n/**\n * This defines FineUploader mode w/ support for uploading to Azure, which provides all the basic\n * functionality of Fine Uploader as well as code to handle uploads directly to Azure.\n * This module inherits all logic from UI & core mode and adds some UI-related logic\n * specific to the upload-to-Azure workflow. Some inherited options and API methods have a special meaning\n * in the context of the Azure uploader.\n */\n(function() {\n \"use strict\";\n\n qq.azure.FineUploader = function(o) {\n var options = {\n failedUploadTextDisplay: {\n mode: \"custom\"\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(options, o, true);\n\n // Inherit instance data from FineUploader, which should in turn inherit from azure.FineUploaderBasic.\n qq.FineUploader.call(this, options, \"azure\");\n };\n\n // Inherit the API methods from FineUploaderBasicS3\n qq.extend(qq.azure.FineUploader.prototype, qq.azure.FineUploaderBasic.prototype);\n\n // Inherit public and private API methods related to UI\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPublicApi);\n qq.extend(qq.azure.FineUploader.prototype, qq.uiPrivateApi);\n\n // Define public & private API methods for this module.\n qq.extend(qq.azure.FineUploader.prototype, {\n });\n}());\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/continue.gif b/libs/bower/bower_components/fine-uploader/dist/continue.gif
new file mode 100644
index 000000000000..303b7fbdcec7
Binary files /dev/null and b/libs/bower/bower_components/fine-uploader/dist/continue.gif differ
diff --git a/libs/bower/bower_components/fine-uploader/dist/dnd.js b/libs/bower/bower_components/fine-uploader/dist/dnd.js
new file mode 100644
index 000000000000..1392415bb360
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/dnd.js
@@ -0,0 +1,1093 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+(function(global) {
+ var qq = function(element) {
+ "use strict";
+ return {
+ hide: function() {
+ element.style.display = "none";
+ return this;
+ },
+ attach: function(type, fn) {
+ if (element.addEventListener) {
+ element.addEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.attachEvent("on" + type, fn);
+ }
+ return function() {
+ qq(element).detach(type, fn);
+ };
+ },
+ detach: function(type, fn) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.detachEvent("on" + type, fn);
+ }
+ return this;
+ },
+ contains: function(descendant) {
+ if (!descendant) {
+ return false;
+ }
+ if (element === descendant) {
+ return true;
+ }
+ if (element.contains) {
+ return element.contains(descendant);
+ } else {
+ return !!(descendant.compareDocumentPosition(element) & 8);
+ }
+ },
+ insertBefore: function(elementB) {
+ elementB.parentNode.insertBefore(element, elementB);
+ return this;
+ },
+ remove: function() {
+ element.parentNode.removeChild(element);
+ return this;
+ },
+ css: function(styles) {
+ if (element.style == null) {
+ throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");
+ }
+ if (styles.opacity != null) {
+ if (typeof element.style.opacity !== "string" && typeof element.filters !== "undefined") {
+ styles.filter = "alpha(opacity=" + Math.round(100 * styles.opacity) + ")";
+ }
+ }
+ qq.extend(element.style, styles);
+ return this;
+ },
+ hasClass: function(name, considerParent) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));
+ },
+ addClass: function(name) {
+ if (!qq(element).hasClass(name)) {
+ element.className += " " + name;
+ }
+ return this;
+ },
+ removeClass: function(name) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ element.className = element.className.replace(re, " ").replace(/^\s+|\s+$/g, "");
+ return this;
+ },
+ getByClass: function(className, first) {
+ var candidates, result = [];
+ if (first && element.querySelector) {
+ return element.querySelector("." + className);
+ } else if (element.querySelectorAll) {
+ return element.querySelectorAll("." + className);
+ }
+ candidates = element.getElementsByTagName("*");
+ qq.each(candidates, function(idx, val) {
+ if (qq(val).hasClass(className)) {
+ result.push(val);
+ }
+ });
+ return first ? result[0] : result;
+ },
+ getFirstByClass: function(className) {
+ return qq(element).getByClass(className, true);
+ },
+ children: function() {
+ var children = [], child = element.firstChild;
+ while (child) {
+ if (child.nodeType === 1) {
+ children.push(child);
+ }
+ child = child.nextSibling;
+ }
+ return children;
+ },
+ setText: function(text) {
+ element.innerText = text;
+ element.textContent = text;
+ return this;
+ },
+ clearText: function() {
+ return qq(element).setText("");
+ },
+ hasAttribute: function(attrName) {
+ var attrVal;
+ if (element.hasAttribute) {
+ if (!element.hasAttribute(attrName)) {
+ return false;
+ }
+ return /^false$/i.exec(element.getAttribute(attrName)) == null;
+ } else {
+ attrVal = element[attrName];
+ if (attrVal === undefined) {
+ return false;
+ }
+ return /^false$/i.exec(attrVal) == null;
+ }
+ }
+ };
+ };
+ (function() {
+ "use strict";
+ qq.canvasToBlob = function(canvas, mime, quality) {
+ return qq.dataUriToBlob(canvas.toDataURL(mime, quality));
+ };
+ qq.dataUriToBlob = function(dataUri) {
+ var arrayBuffer, byteString, createBlob = function(data, mime) {
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }, intArray, mimeString;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return createBlob(arrayBuffer, mimeString);
+ };
+ qq.log = function(message, level) {
+ if (window.console) {
+ if (!level || level === "info") {
+ window.console.log(message);
+ } else {
+ if (window.console[level]) {
+ window.console[level](message);
+ } else {
+ window.console.log("<" + level + "> " + message);
+ }
+ }
+ }
+ };
+ qq.isObject = function(variable) {
+ return variable && !variable.nodeType && Object.prototype.toString.call(variable) === "[object Object]";
+ };
+ qq.isFunction = function(variable) {
+ return typeof variable === "function";
+ };
+ qq.isArray = function(value) {
+ return Object.prototype.toString.call(value) === "[object Array]" || value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer;
+ };
+ qq.isItemList = function(maybeItemList) {
+ return Object.prototype.toString.call(maybeItemList) === "[object DataTransferItemList]";
+ };
+ qq.isNodeList = function(maybeNodeList) {
+ return Object.prototype.toString.call(maybeNodeList) === "[object NodeList]" || maybeNodeList.item && maybeNodeList.namedItem;
+ };
+ qq.isString = function(maybeString) {
+ return Object.prototype.toString.call(maybeString) === "[object String]";
+ };
+ qq.trimStr = function(string) {
+ if (String.prototype.trim) {
+ return string.trim();
+ }
+ return string.replace(/^\s+|\s+$/g, "");
+ };
+ qq.format = function(str) {
+ var args = Array.prototype.slice.call(arguments, 1), newStr = str, nextIdxToReplace = newStr.indexOf("{}");
+ qq.each(args, function(idx, val) {
+ var strBefore = newStr.substring(0, nextIdxToReplace), strAfter = newStr.substring(nextIdxToReplace + 2);
+ newStr = strBefore + val + strAfter;
+ nextIdxToReplace = newStr.indexOf("{}", nextIdxToReplace + val.length);
+ if (nextIdxToReplace < 0) {
+ return false;
+ }
+ });
+ return newStr;
+ };
+ qq.isFile = function(maybeFile) {
+ return window.File && Object.prototype.toString.call(maybeFile) === "[object File]";
+ };
+ qq.isFileList = function(maybeFileList) {
+ return window.FileList && Object.prototype.toString.call(maybeFileList) === "[object FileList]";
+ };
+ qq.isFileOrInput = function(maybeFileOrInput) {
+ return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);
+ };
+ qq.isInput = function(maybeInput, notFile) {
+ var evaluateType = function(type) {
+ var normalizedType = type.toLowerCase();
+ if (notFile) {
+ return normalizedType !== "file";
+ }
+ return normalizedType === "file";
+ };
+ if (window.HTMLInputElement) {
+ if (Object.prototype.toString.call(maybeInput) === "[object HTMLInputElement]") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ if (maybeInput.tagName) {
+ if (maybeInput.tagName.toLowerCase() === "input") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ qq.isBlob = function(maybeBlob) {
+ if (window.Blob && Object.prototype.toString.call(maybeBlob) === "[object Blob]") {
+ return true;
+ }
+ };
+ qq.isXhrUploadSupported = function() {
+ var input = document.createElement("input");
+ input.type = "file";
+ return input.multiple !== undefined && typeof File !== "undefined" && typeof FormData !== "undefined" && typeof qq.createXhrInstance().upload !== "undefined";
+ };
+ qq.createXhrInstance = function() {
+ if (window.XMLHttpRequest) {
+ return new XMLHttpRequest();
+ }
+ try {
+ return new ActiveXObject("MSXML2.XMLHTTP.3.0");
+ } catch (error) {
+ qq.log("Neither XHR or ActiveX are supported!", "error");
+ return null;
+ }
+ };
+ qq.isFolderDropSupported = function(dataTransfer) {
+ return dataTransfer.items && dataTransfer.items.length > 0 && dataTransfer.items[0].webkitGetAsEntry;
+ };
+ qq.isFileChunkingSupported = function() {
+ return !qq.androidStock() && qq.isXhrUploadSupported() && (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);
+ };
+ qq.sliceBlob = function(fileOrBlob, start, end) {
+ var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;
+ return slicer.call(fileOrBlob, start, end);
+ };
+ qq.arrayBufferToHex = function(buffer) {
+ var bytesAsHex = "", bytes = new Uint8Array(buffer);
+ qq.each(bytes, function(idx, byt) {
+ var byteAsHexStr = byt.toString(16);
+ if (byteAsHexStr.length < 2) {
+ byteAsHexStr = "0" + byteAsHexStr;
+ }
+ bytesAsHex += byteAsHexStr;
+ });
+ return bytesAsHex;
+ };
+ qq.readBlobToHex = function(blob, startOffset, length) {
+ var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), fileReader = new FileReader(), promise = new qq.Promise();
+ fileReader.onload = function() {
+ promise.success(qq.arrayBufferToHex(fileReader.result));
+ };
+ fileReader.onerror = promise.failure;
+ fileReader.readAsArrayBuffer(initialBlob);
+ return promise;
+ };
+ qq.extend = function(first, second, extendNested) {
+ qq.each(second, function(prop, val) {
+ if (extendNested && qq.isObject(val)) {
+ if (first[prop] === undefined) {
+ first[prop] = {};
+ }
+ qq.extend(first[prop], val, true);
+ } else {
+ first[prop] = val;
+ }
+ });
+ return first;
+ };
+ qq.override = function(target, sourceFn) {
+ var super_ = {}, source = sourceFn(super_);
+ qq.each(source, function(srcPropName, srcPropVal) {
+ if (target[srcPropName] !== undefined) {
+ super_[srcPropName] = target[srcPropName];
+ }
+ target[srcPropName] = srcPropVal;
+ });
+ return target;
+ };
+ qq.indexOf = function(arr, elt, from) {
+ if (arr.indexOf) {
+ return arr.indexOf(elt, from);
+ }
+ from = from || 0;
+ var len = arr.length;
+ if (from < 0) {
+ from += len;
+ }
+ for (;from < len; from += 1) {
+ if (arr.hasOwnProperty(from) && arr[from] === elt) {
+ return from;
+ }
+ }
+ return -1;
+ };
+ qq.getUniqueId = function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
+ return v.toString(16);
+ });
+ };
+ qq.ie = function() {
+ return navigator.userAgent.indexOf("MSIE") !== -1 || navigator.userAgent.indexOf("Trident") !== -1;
+ };
+ qq.ie7 = function() {
+ return navigator.userAgent.indexOf("MSIE 7") !== -1;
+ };
+ qq.ie8 = function() {
+ return navigator.userAgent.indexOf("MSIE 8") !== -1;
+ };
+ qq.ie10 = function() {
+ return navigator.userAgent.indexOf("MSIE 10") !== -1;
+ };
+ qq.ie11 = function() {
+ return qq.ie() && navigator.userAgent.indexOf("rv:11") !== -1;
+ };
+ qq.edge = function() {
+ return navigator.userAgent.indexOf("Edge") >= 0;
+ };
+ qq.safari = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Apple") !== -1;
+ };
+ qq.chrome = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Google") !== -1;
+ };
+ qq.opera = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Opera") !== -1;
+ };
+ qq.firefox = function() {
+ return !qq.edge() && !qq.ie11() && navigator.userAgent.indexOf("Mozilla") !== -1 && navigator.vendor !== undefined && navigator.vendor === "";
+ };
+ qq.windows = function() {
+ return navigator.platform === "Win32";
+ };
+ qq.android = function() {
+ return navigator.userAgent.toLowerCase().indexOf("android") !== -1;
+ };
+ qq.androidStock = function() {
+ return qq.android() && navigator.userAgent.toLowerCase().indexOf("chrome") < 0;
+ };
+ qq.ios6 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 6_") !== -1;
+ };
+ qq.ios7 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 7_") !== -1;
+ };
+ qq.ios8 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_") !== -1;
+ };
+ qq.ios800 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_0 ") !== -1;
+ };
+ qq.ios = function() {
+ return navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("iPod") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1;
+ };
+ qq.iosChrome = function() {
+ return qq.ios() && navigator.userAgent.indexOf("CriOS") !== -1;
+ };
+ qq.iosSafari = function() {
+ return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf("Safari") !== -1;
+ };
+ qq.iosSafariWebView = function() {
+ return qq.ios() && !qq.iosChrome() && !qq.iosSafari();
+ };
+ qq.preventDefault = function(e) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ };
+ qq.toElement = function() {
+ var div = document.createElement("div");
+ return function(html) {
+ div.innerHTML = html;
+ var element = div.firstChild;
+ div.removeChild(element);
+ return element;
+ };
+ }();
+ qq.each = function(iterableItem, callback) {
+ var keyOrIndex, retVal;
+ if (iterableItem) {
+ if (window.Storage && iterableItem.constructor === window.Storage) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isString(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else {
+ for (keyOrIndex in iterableItem) {
+ if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ };
+ qq.bind = function(oldFunc, context) {
+ if (qq.isFunction(oldFunc)) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ return function() {
+ var newArgs = qq.extend([], args);
+ if (arguments.length) {
+ newArgs = newArgs.concat(Array.prototype.slice.call(arguments));
+ }
+ return oldFunc.apply(context, newArgs);
+ };
+ }
+ throw new Error("first parameter must be a function!");
+ };
+ qq.obj2url = function(obj, temp, prefixDone) {
+ var uristrings = [], prefix = "&", add = function(nextObj, i) {
+ var nextTemp = temp ? /\[\]$/.test(temp) ? temp : temp + "[" + i + "]" : i;
+ if (nextTemp !== "undefined" && i !== "undefined") {
+ uristrings.push(typeof nextObj === "object" ? qq.obj2url(nextObj, nextTemp, true) : Object.prototype.toString.call(nextObj) === "[object Function]" ? encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj));
+ }
+ };
+ if (!prefixDone && temp) {
+ prefix = /\?/.test(temp) ? /\?$/.test(temp) ? "" : "&" : "?";
+ uristrings.push(temp);
+ uristrings.push(qq.obj2url(obj));
+ } else if (Object.prototype.toString.call(obj) === "[object Array]" && typeof obj !== "undefined") {
+ qq.each(obj, function(idx, val) {
+ add(val, idx);
+ });
+ } else if (typeof obj !== "undefined" && obj !== null && typeof obj === "object") {
+ qq.each(obj, function(prop, val) {
+ add(val, prop);
+ });
+ } else {
+ uristrings.push(encodeURIComponent(temp) + "=" + encodeURIComponent(obj));
+ }
+ if (temp) {
+ return uristrings.join(prefix);
+ } else {
+ return uristrings.join(prefix).replace(/^&/, "").replace(/%20/g, "+");
+ }
+ };
+ qq.obj2FormData = function(obj, formData, arrayKeyName) {
+ if (!formData) {
+ formData = new FormData();
+ }
+ qq.each(obj, function(key, val) {
+ key = arrayKeyName ? arrayKeyName + "[" + key + "]" : key;
+ if (qq.isObject(val)) {
+ qq.obj2FormData(val, formData, key);
+ } else if (qq.isFunction(val)) {
+ formData.append(key, val());
+ } else {
+ formData.append(key, val);
+ }
+ });
+ return formData;
+ };
+ qq.obj2Inputs = function(obj, form) {
+ var input;
+ if (!form) {
+ form = document.createElement("form");
+ }
+ qq.obj2FormData(obj, {
+ append: function(key, val) {
+ input = document.createElement("input");
+ input.setAttribute("name", key);
+ input.setAttribute("value", val);
+ form.appendChild(input);
+ }
+ });
+ return form;
+ };
+ qq.parseJson = function(json) {
+ if (window.JSON && qq.isFunction(JSON.parse)) {
+ return JSON.parse(json);
+ } else {
+ return eval("(" + json + ")");
+ }
+ };
+ qq.getExtension = function(filename) {
+ var extIdx = filename.lastIndexOf(".") + 1;
+ if (extIdx > 0) {
+ return filename.substr(extIdx, filename.length - extIdx);
+ }
+ };
+ qq.getFilename = function(blobOrFileInput) {
+ if (qq.isInput(blobOrFileInput)) {
+ return blobOrFileInput.value.replace(/.*(\/|\\)/, "");
+ } else if (qq.isFile(blobOrFileInput)) {
+ if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {
+ return blobOrFileInput.fileName;
+ }
+ }
+ return blobOrFileInput.name;
+ };
+ qq.DisposeSupport = function() {
+ var disposers = [];
+ return {
+ dispose: function() {
+ var disposer;
+ do {
+ disposer = disposers.shift();
+ if (disposer) {
+ disposer();
+ }
+ } while (disposer);
+ },
+ attach: function() {
+ var args = arguments;
+ this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));
+ },
+ addDisposer: function(disposeFunction) {
+ disposers.push(disposeFunction);
+ }
+ };
+ };
+ })();
+ (function() {
+ "use strict";
+ if (typeof define === "function" && define.amd) {
+ define(function() {
+ return qq;
+ });
+ } else if (typeof module !== "undefined" && module.exports) {
+ module.exports = qq;
+ } else {
+ global.qq = qq;
+ }
+ })();
+ qq.version = "5.13.0";
+ qq.supportedFeatures = function() {
+ "use strict";
+ var supportsUploading, supportsUploadingBlobs, supportsFileDrop, supportsAjaxFileUploading, supportsFolderDrop, supportsChunking, supportsResume, supportsUploadViaPaste, supportsUploadCors, supportsDeleteFileXdr, supportsDeleteFileCorsXhr, supportsDeleteFileCors, supportsFolderSelection, supportsImagePreviews, supportsUploadProgress;
+ function testSupportsFileInputElement() {
+ var supported = true, tempInput;
+ try {
+ tempInput = document.createElement("input");
+ tempInput.type = "file";
+ qq(tempInput).hide();
+ if (tempInput.disabled) {
+ supported = false;
+ }
+ } catch (ex) {
+ supported = false;
+ }
+ return supported;
+ }
+ function isChrome21OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/) !== undefined;
+ }
+ function isChrome14OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/) !== undefined;
+ }
+ function isCrossOriginXhrSupported() {
+ if (window.XMLHttpRequest) {
+ var xhr = qq.createXhrInstance();
+ return xhr.withCredentials !== undefined;
+ }
+ return false;
+ }
+ function isXdrSupported() {
+ return window.XDomainRequest !== undefined;
+ }
+ function isCrossOriginAjaxSupported() {
+ if (isCrossOriginXhrSupported()) {
+ return true;
+ }
+ return isXdrSupported();
+ }
+ function isFolderSelectionSupported() {
+ return document.createElement("input").webkitdirectory !== undefined;
+ }
+ function isLocalStorageSupported() {
+ try {
+ return !!window.localStorage && qq.isFunction(window.localStorage.setItem);
+ } catch (error) {
+ return false;
+ }
+ }
+ function isDragAndDropSupported() {
+ var span = document.createElement("span");
+ return ("draggable" in span || "ondragstart" in span && "ondrop" in span) && !qq.android() && !qq.ios();
+ }
+ supportsUploading = testSupportsFileInputElement();
+ supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();
+ supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();
+ supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();
+ supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();
+ supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();
+ supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();
+ supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();
+ supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);
+ supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();
+ supportsDeleteFileXdr = isXdrSupported();
+ supportsDeleteFileCors = isCrossOriginAjaxSupported();
+ supportsFolderSelection = isFolderSelectionSupported();
+ supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;
+ supportsUploadProgress = function() {
+ if (supportsAjaxFileUploading) {
+ return !qq.androidStock() && !qq.iosChrome();
+ }
+ return false;
+ }();
+ return {
+ ajaxUploading: supportsAjaxFileUploading,
+ blobUploading: supportsUploadingBlobs,
+ canDetermineSize: supportsAjaxFileUploading,
+ chunking: supportsChunking,
+ deleteFileCors: supportsDeleteFileCors,
+ deleteFileCorsXdr: supportsDeleteFileXdr,
+ deleteFileCorsXhr: supportsDeleteFileCorsXhr,
+ dialogElement: !!window.HTMLDialogElement,
+ fileDrop: supportsFileDrop,
+ folderDrop: supportsFolderDrop,
+ folderSelection: supportsFolderSelection,
+ imagePreviews: supportsImagePreviews,
+ imageValidation: supportsImagePreviews,
+ itemSizeValidation: supportsAjaxFileUploading,
+ pause: supportsChunking,
+ progressBar: supportsUploadProgress,
+ resume: supportsResume,
+ scaling: supportsImagePreviews && supportsUploadingBlobs,
+ tiffPreviews: qq.safari(),
+ unlimitedScaledImageSize: !qq.ios(),
+ uploading: supportsUploading,
+ uploadCors: supportsUploadCors,
+ uploadCustomHeaders: supportsAjaxFileUploading,
+ uploadNonMultipart: supportsAjaxFileUploading,
+ uploadViaPaste: supportsUploadViaPaste
+ };
+ }();
+ qq.isGenericPromise = function(maybePromise) {
+ "use strict";
+ return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));
+ };
+ qq.Promise = function() {
+ "use strict";
+ var successArgs, failureArgs, successCallbacks = [], failureCallbacks = [], doneCallbacks = [], state = 0;
+ qq.extend(this, {
+ then: function(onSuccess, onFailure) {
+ if (state === 0) {
+ if (onSuccess) {
+ successCallbacks.push(onSuccess);
+ }
+ if (onFailure) {
+ failureCallbacks.push(onFailure);
+ }
+ } else if (state === -1) {
+ onFailure && onFailure.apply(null, failureArgs);
+ } else if (onSuccess) {
+ onSuccess.apply(null, successArgs);
+ }
+ return this;
+ },
+ done: function(callback) {
+ if (state === 0) {
+ doneCallbacks.push(callback);
+ } else {
+ callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);
+ }
+ return this;
+ },
+ success: function() {
+ state = 1;
+ successArgs = arguments;
+ if (successCallbacks.length) {
+ qq.each(successCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ return this;
+ },
+ failure: function() {
+ state = -1;
+ failureArgs = arguments;
+ if (failureCallbacks.length) {
+ qq.each(failureCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ return this;
+ }
+ });
+ };
+ qq.DragAndDrop = function(o) {
+ "use strict";
+ var options, HIDE_ZONES_EVENT_NAME = "qq-hidezones", HIDE_BEFORE_ENTER_ATTR = "qq-hide-dropzone", uploadDropZones = [], droppedFiles = [], disposeSupport = new qq.DisposeSupport();
+ options = {
+ dropZoneElements: [],
+ allowMultipleItems: true,
+ classes: {
+ dropActive: null
+ },
+ callbacks: new qq.DragAndDrop.callbacks()
+ };
+ qq.extend(options, o, true);
+ function uploadDroppedFiles(files, uploadDropZone) {
+ var filesAsArray = Array.prototype.slice.call(files);
+ options.callbacks.dropLog("Grabbed " + files.length + " dropped files.");
+ uploadDropZone.dropDisabled(false);
+ options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());
+ }
+ function traverseFileTree(entry) {
+ var parseEntryPromise = new qq.Promise();
+ if (entry.isFile) {
+ entry.file(function(file) {
+ var name = entry.name, fullPath = entry.fullPath, indexOfNameInFullPath = fullPath.indexOf(name);
+ fullPath = fullPath.substr(0, indexOfNameInFullPath);
+ if (fullPath.charAt(0) === "/") {
+ fullPath = fullPath.substr(1);
+ }
+ file.qqPath = fullPath;
+ droppedFiles.push(file);
+ parseEntryPromise.success();
+ }, function(fileError) {
+ options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error");
+ parseEntryPromise.failure();
+ });
+ } else if (entry.isDirectory) {
+ getFilesInDirectory(entry).then(function allEntriesRead(entries) {
+ var entriesLeft = entries.length;
+ qq.each(entries, function(idx, entry) {
+ traverseFileTree(entry).done(function() {
+ entriesLeft -= 1;
+ if (entriesLeft === 0) {
+ parseEntryPromise.success();
+ }
+ });
+ });
+ if (!entries.length) {
+ parseEntryPromise.success();
+ }
+ }, function readFailure(fileError) {
+ options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error");
+ parseEntryPromise.failure();
+ });
+ }
+ return parseEntryPromise;
+ }
+ function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {
+ var promise = existingPromise || new qq.Promise(), dirReader = reader || entry.createReader();
+ dirReader.readEntries(function readSuccess(entries) {
+ var newEntries = accumEntries ? accumEntries.concat(entries) : entries;
+ if (entries.length) {
+ setTimeout(function() {
+ getFilesInDirectory(entry, dirReader, newEntries, promise);
+ }, 0);
+ } else {
+ promise.success(newEntries);
+ }
+ }, promise.failure);
+ return promise;
+ }
+ function handleDataTransfer(dataTransfer, uploadDropZone) {
+ var pendingFolderPromises = [], handleDataTransferPromise = new qq.Promise();
+ options.callbacks.processingDroppedFiles();
+ uploadDropZone.dropDisabled(true);
+ if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {
+ options.callbacks.processingDroppedFilesComplete([]);
+ options.callbacks.dropError("tooManyFilesError", "");
+ uploadDropZone.dropDisabled(false);
+ handleDataTransferPromise.failure();
+ } else {
+ droppedFiles = [];
+ if (qq.isFolderDropSupported(dataTransfer)) {
+ qq.each(dataTransfer.items, function(idx, item) {
+ var entry = item.webkitGetAsEntry();
+ if (entry) {
+ if (entry.isFile) {
+ droppedFiles.push(item.getAsFile());
+ } else {
+ pendingFolderPromises.push(traverseFileTree(entry).done(function() {
+ pendingFolderPromises.pop();
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }));
+ }
+ }
+ });
+ } else {
+ droppedFiles = dataTransfer.files;
+ }
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }
+ return handleDataTransferPromise;
+ }
+ function setupDropzone(dropArea) {
+ var dropZone = new qq.UploadDropZone({
+ HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,
+ element: dropArea,
+ onEnter: function(e) {
+ qq(dropArea).addClass(options.classes.dropActive);
+ e.stopPropagation();
+ },
+ onLeaveNotDescendants: function(e) {
+ qq(dropArea).removeClass(options.classes.dropActive);
+ },
+ onDrop: function(e) {
+ handleDataTransfer(e.dataTransfer, dropZone).then(function() {
+ uploadDroppedFiles(droppedFiles, dropZone);
+ }, function() {
+ options.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.", "error");
+ });
+ }
+ });
+ disposeSupport.addDisposer(function() {
+ dropZone.dispose();
+ });
+ qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();
+ uploadDropZones.push(dropZone);
+ return dropZone;
+ }
+ function isFileDrag(dragEvent) {
+ var fileDrag;
+ qq.each(dragEvent.dataTransfer.types, function(key, val) {
+ if (val === "Files") {
+ fileDrag = true;
+ return false;
+ }
+ });
+ return fileDrag;
+ }
+ function leavingDocumentOut(e) {
+ if (qq.firefox()) {
+ return !e.relatedTarget;
+ }
+ if (qq.safari()) {
+ return e.x < 0 || e.y < 0;
+ }
+ return e.x === 0 && e.y === 0;
+ }
+ function setupDragDrop() {
+ var dropZones = options.dropZoneElements, maybeHideDropZones = function() {
+ setTimeout(function() {
+ qq.each(dropZones, function(idx, dropZone) {
+ qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();
+ qq(dropZone).removeClass(options.classes.dropActive);
+ });
+ }, 10);
+ };
+ qq.each(dropZones, function(idx, dropZone) {
+ var uploadDropZone = setupDropzone(dropZone);
+ if (dropZones.length && qq.supportedFeatures.fileDrop) {
+ disposeSupport.attach(document, "dragenter", function(e) {
+ if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {
+ qq.each(dropZones, function(idx, dropZone) {
+ if (dropZone instanceof HTMLElement && qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {
+ qq(dropZone).css({
+ display: "block"
+ });
+ }
+ });
+ }
+ });
+ }
+ });
+ disposeSupport.attach(document, "dragleave", function(e) {
+ if (leavingDocumentOut(e)) {
+ maybeHideDropZones();
+ }
+ });
+ disposeSupport.attach(qq(document).children()[0], "mouseenter", function(e) {
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, "drop", function(e) {
+ e.preventDefault();
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);
+ }
+ setupDragDrop();
+ qq.extend(this, {
+ setupExtraDropzone: function(element) {
+ options.dropZoneElements.push(element);
+ setupDropzone(element);
+ },
+ removeDropzone: function(element) {
+ var i, dzs = options.dropZoneElements;
+ for (i in dzs) {
+ if (dzs[i] === element) {
+ return dzs.splice(i, 1);
+ }
+ }
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ qq.each(uploadDropZones, function(idx, dropZone) {
+ dropZone.dispose();
+ });
+ }
+ });
+ };
+ qq.DragAndDrop.callbacks = function() {
+ "use strict";
+ return {
+ processingDroppedFiles: function() {},
+ processingDroppedFilesComplete: function(files, targetEl) {},
+ dropError: function(code, errorSpecifics) {
+ qq.log("Drag & drop error code '" + code + " with these specifics: '" + errorSpecifics + "'", "error");
+ },
+ dropLog: function(message, level) {
+ qq.log(message, level);
+ }
+ };
+ };
+ qq.UploadDropZone = function(o) {
+ "use strict";
+ var disposeSupport = new qq.DisposeSupport(), options, element, preventDrop, dropOutsideDisabled;
+ options = {
+ element: null,
+ onEnter: function(e) {},
+ onLeave: function(e) {},
+ onLeaveNotDescendants: function(e) {},
+ onDrop: function(e) {}
+ };
+ qq.extend(options, o);
+ element = options.element;
+ function dragoverShouldBeCanceled() {
+ return qq.safari() || qq.firefox() && qq.windows();
+ }
+ function disableDropOutside(e) {
+ if (!dropOutsideDisabled) {
+ if (dragoverShouldBeCanceled) {
+ disposeSupport.attach(document, "dragover", function(e) {
+ e.preventDefault();
+ });
+ } else {
+ disposeSupport.attach(document, "dragover", function(e) {
+ if (e.dataTransfer) {
+ e.dataTransfer.dropEffect = "none";
+ e.preventDefault();
+ }
+ });
+ }
+ dropOutsideDisabled = true;
+ }
+ }
+ function isValidFileDrag(e) {
+ if (!qq.supportedFeatures.fileDrop) {
+ return false;
+ }
+ var effectTest, dt = e.dataTransfer, isSafari = qq.safari();
+ effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== "none";
+ return dt && effectTest && (dt.files || !isSafari && dt.types.contains && dt.types.contains("Files"));
+ }
+ function isOrSetDropDisabled(isDisabled) {
+ if (isDisabled !== undefined) {
+ preventDrop = isDisabled;
+ }
+ return preventDrop;
+ }
+ function triggerHidezonesEvent() {
+ var hideZonesEvent;
+ function triggerUsingOldApi() {
+ hideZonesEvent = document.createEvent("Event");
+ hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);
+ }
+ if (window.CustomEvent) {
+ try {
+ hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);
+ } catch (err) {
+ triggerUsingOldApi();
+ }
+ } else {
+ triggerUsingOldApi();
+ }
+ document.dispatchEvent(hideZonesEvent);
+ }
+ function attachEvents() {
+ disposeSupport.attach(element, "dragover", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;
+ if (effect === "move" || effect === "linkMove") {
+ e.dataTransfer.dropEffect = "move";
+ } else {
+ e.dataTransfer.dropEffect = "copy";
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ disposeSupport.attach(element, "dragenter", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onEnter(e);
+ }
+ });
+ disposeSupport.attach(element, "dragleave", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onLeave(e);
+ var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
+ if (qq(this).contains(relatedTarget)) {
+ return;
+ }
+ options.onLeaveNotDescendants(e);
+ });
+ disposeSupport.attach(element, "drop", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ options.onDrop(e);
+ triggerHidezonesEvent();
+ }
+ });
+ }
+ disableDropOutside();
+ attachEvents();
+ qq.extend(this, {
+ dropDisabled: function(isDisabled) {
+ return isOrSetDropDisabled(isDisabled);
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ },
+ getElement: function() {
+ return element;
+ }
+ });
+ };
+})(window);
+//# sourceMappingURL=dnd.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/dnd.js.map b/libs/bower/bower_components/fine-uploader/dist/dnd.js.map
new file mode 100644
index 000000000000..d32d1e967f40
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/dnd.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/dnd.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","intArray","mimeString","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","testSupportsFileInputElement","supported","tempInput","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","DragAndDrop","o","options","HIDE_ZONES_EVENT_NAME","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","droppedFiles","disposeSupport","dropZoneElements","allowMultipleItems","classes","dropActive","callbacks","uploadDroppedFiles","files","uploadDropZone","filesAsArray","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","entry","parseEntryPromise","file","fullPath","indexOfNameInFullPath","qqPath","fileError","code","isDirectory","getFilesInDirectory","allEntriesRead","entries","entriesLeft","readFailure","reader","accumEntries","existingPromise","dirReader","createReader","readEntries","readSuccess","newEntries","setTimeout","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","dropError","getAsFile","pop","setupDropzone","dropArea","dropZone","UploadDropZone","onEnter","stopPropagation","onLeaveNotDescendants","onDrop","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","relatedTarget","x","y","setupDragDrop","dropZones","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","splice","targetEl","errorSpecifics","preventDrop","dropOutsideDisabled","onLeave","dragoverShouldBeCanceled","disableDropOutside","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","isOrSetDropDisabled","isDisabled","triggerHidezonesEvent","hideZonesEvent","triggerUsingOldApi","createEvent","initEvent","CustomEvent","err","dispatchEvent","attachEvents","effect","elementFromPoint","clientX","clientY"],"mappings":"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","file":"dnd.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/*globals qq, document, CustomEvent*/\nqq.DragAndDrop = function(o) {\n \"use strict\";\n\n var options,\n HIDE_ZONES_EVENT_NAME = \"qq-hidezones\",\n HIDE_BEFORE_ENTER_ATTR = \"qq-hide-dropzone\",\n uploadDropZones = [],\n droppedFiles = [],\n disposeSupport = new qq.DisposeSupport();\n\n options = {\n dropZoneElements: [],\n allowMultipleItems: true,\n classes: {\n dropActive: null\n },\n callbacks: new qq.DragAndDrop.callbacks()\n };\n\n qq.extend(options, o, true);\n\n function uploadDroppedFiles(files, uploadDropZone) {\n // We need to convert the `FileList` to an actual `Array` to avoid iteration issues\n var filesAsArray = Array.prototype.slice.call(files);\n\n options.callbacks.dropLog(\"Grabbed \" + files.length + \" dropped files.\");\n uploadDropZone.dropDisabled(false);\n options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());\n }\n\n function traverseFileTree(entry) {\n var parseEntryPromise = new qq.Promise();\n\n if (entry.isFile) {\n entry.file(function(file) {\n var name = entry.name,\n fullPath = entry.fullPath,\n indexOfNameInFullPath = fullPath.indexOf(name);\n\n // remove file name from full path string\n fullPath = fullPath.substr(0, indexOfNameInFullPath);\n\n // remove leading slash in full path string\n if (fullPath.charAt(0) === \"/\") {\n fullPath = fullPath.substr(1);\n }\n\n file.qqPath = fullPath;\n droppedFiles.push(file);\n parseEntryPromise.success();\n },\n function(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n });\n }\n else if (entry.isDirectory) {\n getFilesInDirectory(entry).then(\n function allEntriesRead(entries) {\n var entriesLeft = entries.length;\n\n qq.each(entries, function(idx, entry) {\n traverseFileTree(entry).done(function() {\n entriesLeft -= 1;\n\n if (entriesLeft === 0) {\n parseEntryPromise.success();\n }\n });\n });\n\n if (!entries.length) {\n parseEntryPromise.success();\n }\n },\n\n function readFailure(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n }\n );\n }\n\n return parseEntryPromise;\n }\n\n // Promissory. Guaranteed to read all files in the root of the passed directory.\n function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {\n var promise = existingPromise || new qq.Promise(),\n dirReader = reader || entry.createReader();\n\n dirReader.readEntries(\n function readSuccess(entries) {\n var newEntries = accumEntries ? accumEntries.concat(entries) : entries;\n\n if (entries.length) {\n setTimeout(function() { // prevent stack overflow, however unlikely\n getFilesInDirectory(entry, dirReader, newEntries, promise);\n }, 0);\n }\n else {\n promise.success(newEntries);\n }\n },\n\n promise.failure\n );\n\n return promise;\n }\n\n function handleDataTransfer(dataTransfer, uploadDropZone) {\n var pendingFolderPromises = [],\n handleDataTransferPromise = new qq.Promise();\n\n options.callbacks.processingDroppedFiles();\n uploadDropZone.dropDisabled(true);\n\n if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.firefox()) {\n return !e.relatedTarget;\n }\n\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n e.preventDefault();\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n // dt.types.contains check is for firefox\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains(\"Files\")));\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n};\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/dnd.min.js b/libs/bower/bower_components/fine-uploader/dist/dnd.min.js
new file mode 100644
index 000000000000..e9825a5607b4
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/dnd.min.js
@@ -0,0 +1,3 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+!function(global){var qq=function(e){"use strict";return{hide:function(){return e.style.display="none",this},attach:function(n,t){return e.addEventListener?e.addEventListener(n,t,!1):e.attachEvent&&e.attachEvent("on"+n,t),function(){qq(e).detach(n,t)}},detach:function(n,t){return e.removeEventListener?e.removeEventListener(n,t,!1):e.attachEvent&&e.detachEvent("on"+n,t),this},contains:function(n){return!!n&&(e===n||(e.contains?e.contains(n):!!(8&n.compareDocumentPosition(e))))},insertBefore:function(n){return n.parentNode.insertBefore(e,n),this},remove:function(){return e.parentNode.removeChild(e),this},css:function(n){if(null==e.style)throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");return null!=n.opacity&&"string"!=typeof e.style.opacity&&"undefined"!=typeof e.filters&&(n.filter="alpha(opacity="+Math.round(100*n.opacity)+")"),qq.extend(e.style,n),this},hasClass:function(n,t){var r=new RegExp("(^| )"+n+"( |$)");return r.test(e.className)||!(!t||!r.test(e.parentNode.className))},addClass:function(n){return qq(e).hasClass(n)||(e.className+=" "+n),this},removeClass:function(n){var t=new RegExp("(^| )"+n+"( |$)");return e.className=e.className.replace(t," ").replace(/^\s+|\s+$/g,""),this},getByClass:function(n,t){var r,o=[];return t&&e.querySelector?e.querySelector("."+n):e.querySelectorAll?e.querySelectorAll("."+n):(r=e.getElementsByTagName("*"),qq.each(r,function(e,t){qq(t).hasClass(n)&&o.push(t)}),t?o[0]:o)},getFirstByClass:function(n){return qq(e).getByClass(n,!0)},children:function(){for(var n=[],t=e.firstChild;t;)1===t.nodeType&&n.push(t),t=t.nextSibling;return n},setText:function(n){return e.innerText=n,e.textContent=n,this},clearText:function(){return qq(e).setText("")},hasAttribute:function(n){var t;return e.hasAttribute?!!e.hasAttribute(n)&&null==/^false$/i.exec(e.getAttribute(n)):(t=e[n],void 0!==t&&null==/^false$/i.exec(t))}}};!function(){"use strict";qq.canvasToBlob=function(e,n,t){return qq.dataUriToBlob(e.toDataURL(n,t))},qq.dataUriToBlob=function(e){var n,t,r,o,i=function(e,n){var t=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,r=t&&new t;return r?(r.append(e),r.getBlob(n)):new Blob([e],{type:n})};return t=e.split(",")[0].indexOf("base64")>=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),o=e.split(",")[0].split(":")[1].split(";")[0],n=new ArrayBuffer(t.length),r=new Uint8Array(n),qq.each(t,function(e,n){r[e]=n.charCodeAt(0)}),i(n,o)},qq.log=function(e,n){window.console&&(n&&"info"!==n?window.console[n]?window.console[n](e):window.console.log("<"+n+"> "+e):window.console.log(e))},qq.isObject=function(e){return e&&!e.nodeType&&"[object Object]"===Object.prototype.toString.call(e)},qq.isFunction=function(e){return"function"==typeof e},qq.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)||e&&window.ArrayBuffer&&e.buffer&&e.buffer.constructor===ArrayBuffer},qq.isItemList=function(e){return"[object DataTransferItemList]"===Object.prototype.toString.call(e)},qq.isNodeList=function(e){return"[object NodeList]"===Object.prototype.toString.call(e)||e.item&&e.namedItem},qq.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},qq.trimStr=function(e){return String.prototype.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},qq.format=function(e){var n=Array.prototype.slice.call(arguments,1),t=e,r=t.indexOf("{}");return qq.each(n,function(e,n){var o=t.substring(0,r),i=t.substring(r+2);if(t=o+n+i,r=t.indexOf("{}",r+n.length),r<0)return!1}),t},qq.isFile=function(e){return window.File&&"[object File]"===Object.prototype.toString.call(e)},qq.isFileList=function(e){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(e)},qq.isFileOrInput=function(e){return qq.isFile(e)||qq.isInput(e)},qq.isInput=function(e,n){var t=function(e){var t=e.toLowerCase();return n?"file"!==t:"file"===t};return!!(window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(e)&&e.type&&t(e.type))||!!(e.tagName&&"input"===e.tagName.toLowerCase()&&e.type&&t(e.type))},qq.isBlob=function(e){if(window.Blob&&"[object Blob]"===Object.prototype.toString.call(e))return!0},qq.isXhrUploadSupported=function(){var e=document.createElement("input");return e.type="file",void 0!==e.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&"undefined"!=typeof qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(e){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(e){return e.items&&e.items.length>0&&e.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(e,n,t){var r=e.slice||e.mozSlice||e.webkitSlice;return r.call(e,n,t)},qq.arrayBufferToHex=function(e){var n="",t=new Uint8Array(e);return qq.each(t,function(e,t){var r=t.toString(16);r.length<2&&(r="0"+r),n+=r}),n},qq.readBlobToHex=function(e,n,t){var r=qq.sliceBlob(e,n,n+t),o=new FileReader,i=new qq.Promise;return o.onload=function(){i.success(qq.arrayBufferToHex(o.result))},o.onerror=i.failure,o.readAsArrayBuffer(r),i},qq.extend=function(e,n,t){return qq.each(n,function(n,r){t&&qq.isObject(r)?(void 0===e[n]&&(e[n]={}),qq.extend(e[n],r,!0)):e[n]=r}),e},qq.override=function(e,n){var t={},r=n(t);return qq.each(r,function(n,r){void 0!==e[n]&&(t[n]=e[n]),e[n]=r}),e},qq.indexOf=function(e,n,t){if(e.indexOf)return e.indexOf(n,t);t=t||0;var r=e.length;for(t<0&&(t+=r);t=0},qq.safari=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Apple")!==-1},qq.chrome=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Google")!==-1},qq.opera=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Opera")!==-1},qq.firefox=function(){return!qq.edge()&&!qq.ie11()&&navigator.userAgent.indexOf("Mozilla")!==-1&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return navigator.userAgent.toLowerCase().indexOf("android")!==-1},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 6_")!==-1},qq.ios7=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 7_")!==-1},qq.ios8=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_")!==-1},qq.ios800=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_0 ")!==-1},qq.ios=function(){return navigator.userAgent.indexOf("iPad")!==-1||navigator.userAgent.indexOf("iPod")!==-1||navigator.userAgent.indexOf("iPhone")!==-1},qq.iosChrome=function(){return qq.ios()&&navigator.userAgent.indexOf("CriOS")!==-1},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&navigator.userAgent.indexOf("Safari")!==-1},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},qq.toElement=function(){var e=document.createElement("div");return function(n){e.innerHTML=n;var t=e.firstChild;return e.removeChild(t),t}}(),qq.each=function(e,n){var t,r;if(e)if(window.Storage&&e.constructor===window.Storage)for(t=0;t0)return e.substr(n,e.length-n)},qq.getFilename=function(e){return qq.isInput(e)?e.value.replace(/.*(\/|\\)/,""):qq.isFile(e)&&null!==e.fileName&&void 0!==e.fileName?e.fileName:e.name},qq.DisposeSupport=function(){var e=[];return{dispose:function(){var n;do n=e.shift(),n&&n();while(n)},attach:function(){var e=arguments;this.addDisposer(qq(e[0]).attach.apply(this,Array.prototype.slice.call(arguments,1)))},addDisposer:function(n){e.push(n)}}}}(),function(){"use strict";"function"==typeof define&&define.amd?define(function(){return qq}):"undefined"!=typeof module&&module.exports?module.exports=qq:global.qq=qq}(),qq.version="5.13.0",qq.supportedFeatures=function(){"use strict";function e(){var e,n=!0;try{e=document.createElement("input"),e.type="file",qq(e).hide(),e.disabled&&(n=!1)}catch(e){n=!1}return n}function n(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/)}function t(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/)}function r(){if(window.XMLHttpRequest){var e=qq.createXhrInstance();return void 0!==e.withCredentials}return!1}function o(){return void 0!==window.XDomainRequest}function i(){return!!r()||o()}function a(){return void 0!==document.createElement("input").webkitdirectory}function u(){try{return!!window.localStorage&&qq.isFunction(window.localStorage.setItem)}catch(e){return!1}}function c(){var e=document.createElement("span");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&!qq.android()&&!qq.ios()}var s,l,q,f,d,p,g,v,h,m,y,b,w,x,E;return s=e(),f=s&&qq.isXhrUploadSupported(),l=f&&!qq.androidStock(),q=f&&c(),d=q&&n(),p=f&&qq.isFileChunkingSupported(),g=f&&p&&u(),v=f&&t(),h=s&&(void 0!==window.postMessage||f),y=r(),m=o(),b=i(),w=a(),x=f&&void 0!==window.FileReader,E=function(){return!!f&&(!qq.androidStock()&&!qq.iosChrome())}(),{ajaxUploading:f,blobUploading:l,canDetermineSize:f,chunking:p,deleteFileCors:b,deleteFileCorsXdr:m,deleteFileCorsXhr:y,dialogElement:!!window.HTMLDialogElement,fileDrop:q,folderDrop:d,folderSelection:w,imagePreviews:x,imageValidation:x,itemSizeValidation:f,pause:p,progressBar:E,resume:g,scaling:x&&l,tiffPreviews:qq.safari(),unlimitedScaledImageSize:!qq.ios(),uploading:s,uploadCors:h,uploadCustomHeaders:f,uploadNonMultipart:f,uploadViaPaste:v}}(),qq.isGenericPromise=function(e){"use strict";return!!(e&&e.then&&qq.isFunction(e.then))},qq.Promise=function(){"use strict";var e,n,t=[],r=[],o=[],i=0;qq.extend(this,{then:function(o,a){return 0===i?(o&&t.push(o),a&&r.push(a)):i===-1?a&&a.apply(null,n):o&&o.apply(null,e),this},done:function(t){return 0===i?o.push(t):t.apply(null,void 0===n?e:n),this},success:function(){return i=1,e=arguments,t.length&&qq.each(t,function(n,t){t.apply(null,e)}),o.length&&qq.each(o,function(n,t){t.apply(null,e)}),this},failure:function(){return i=-1,n=arguments,r.length&&qq.each(r,function(e,t){t.apply(null,n)}),o.length&&qq.each(o,function(e,t){t.apply(null,n)}),this}})},qq.DragAndDrop=function(e){"use strict";function n(e,n){var t=Array.prototype.slice.call(e);s.callbacks.dropLog("Grabbed "+e.length+" dropped files."),n.dropDisabled(!1),s.callbacks.processingDroppedFilesComplete(t,n.getElement())}function t(e){var n=new qq.Promise;return e.isFile?e.file(function(t){var r=e.name,o=e.fullPath,i=o.indexOf(r);o=o.substr(0,i),"/"===o.charAt(0)&&(o=o.substr(1)),t.qqPath=o,d.push(t),n.success()},function(t){s.callbacks.dropLog("Problem parsing '"+e.fullPath+"'. FileError code "+t.code+".","error"),n.failure()}):e.isDirectory&&r(e).then(function(e){var r=e.length;qq.each(e,function(e,o){t(o).done(function(){r-=1,0===r&&n.success()})}),e.length||n.success()},function(t){s.callbacks.dropLog("Problem parsing '"+e.fullPath+"'. FileError code "+t.code+".","error"),n.failure()}),n}function r(e,n,t,o){var i=o||new qq.Promise,a=n||e.createReader();return a.readEntries(function(n){var o=t?t.concat(n):n;n.length?setTimeout(function(){r(e,a,o,i)},0):i.success(o)},i.failure),i}function o(e,n){var r=[],o=new qq.Promise;return s.callbacks.processingDroppedFiles(),n.dropDisabled(!0),e.files.length>1&&!s.allowMultipleItems?(s.callbacks.processingDroppedFilesComplete([]),s.callbacks.dropError("tooManyFilesError",""),n.dropDisabled(!1),o.failure()):(d=[],qq.isFolderDropSupported(e)?qq.each(e.items,function(e,n){var i=n.webkitGetAsEntry();i&&(i.isFile?d.push(n.getAsFile()):r.push(t(i).done(function(){r.pop(),0===r.length&&o.success()})))}):d=e.files,0===r.length&&o.success()),o}function i(e){var t=new qq.UploadDropZone({HIDE_ZONES_EVENT_NAME:l,element:e,onEnter:function(n){qq(e).addClass(s.classes.dropActive),n.stopPropagation()},onLeaveNotDescendants:function(n){qq(e).removeClass(s.classes.dropActive)},onDrop:function(e){o(e.dataTransfer,t).then(function(){n(d,t)},function(){s.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.","error")})}});return p.addDisposer(function(){t.dispose()}),qq(e).hasAttribute(q)&&qq(e).hide(),f.push(t),t}function a(e){var n;return qq.each(e.dataTransfer.types,function(e,t){if("Files"===t)return n=!0,!1}),n}function u(e){return qq.firefox()?!e.relatedTarget:qq.safari()?e.x<0||e.y<0:0===e.x&&0===e.y}function c(){var e=s.dropZoneElements,n=function(){setTimeout(function(){qq.each(e,function(e,n){qq(n).hasAttribute(q)&&qq(n).hide(),qq(n).removeClass(s.classes.dropActive)})},10)};qq.each(e,function(n,t){var r=i(t);e.length&&qq.supportedFeatures.fileDrop&&p.attach(document,"dragenter",function(n){!r.dropDisabled()&&a(n)&&qq.each(e,function(e,n){n instanceof HTMLElement&&qq(n).hasAttribute(q)&&qq(n).css({display:"block"})})})}),p.attach(document,"dragleave",function(e){u(e)&&n()}),p.attach(qq(document).children()[0],"mouseenter",function(e){n()}),p.attach(document,"drop",function(e){e.preventDefault(),n()}),p.attach(document,l,n)}var s,l="qq-hidezones",q="qq-hide-dropzone",f=[],d=[],p=new qq.DisposeSupport;s={dropZoneElements:[],allowMultipleItems:!0,classes:{dropActive:null},callbacks:new qq.DragAndDrop.callbacks},qq.extend(s,e,!0),c(),qq.extend(this,{setupExtraDropzone:function(e){s.dropZoneElements.push(e),i(e)},removeDropzone:function(e){var n,t=s.dropZoneElements;for(n in t)if(t[n]===e)return t.splice(n,1)},dispose:function(){p.dispose(),qq.each(f,function(e,n){n.dispose()})}})},qq.DragAndDrop.callbacks=function(){"use strict";return{processingDroppedFiles:function(){},processingDroppedFilesComplete:function(e,n){},dropError:function(e,n){qq.log("Drag & drop error code '"+e+" with these specifics: '"+n+"'","error")},dropLog:function(e,n){qq.log(e,n)}}},qq.UploadDropZone=function(e){"use strict";function n(){return qq.safari()||qq.firefox()&&qq.windows()}function t(e){l||(n?q.attach(document,"dragover",function(e){e.preventDefault()}):q.attach(document,"dragover",function(e){e.dataTransfer&&(e.dataTransfer.dropEffect="none",e.preventDefault())}),l=!0)}function r(e){if(!qq.supportedFeatures.fileDrop)return!1;var n,t=e.dataTransfer,r=qq.safari();return n=!(!qq.ie()||!qq.supportedFeatures.fileDrop)||"none"!==t.effectAllowed,t&&n&&(t.files||!r&&t.types.contains&&t.types.contains("Files"))}function o(e){return void 0!==e&&(s=e),s}function i(){function e(){n=document.createEvent("Event"),n.initEvent(u.HIDE_ZONES_EVENT_NAME,!0,!0)}var n;if(window.CustomEvent)try{n=new CustomEvent(u.HIDE_ZONES_EVENT_NAME)}catch(n){e()}else e();document.dispatchEvent(n)}function a(){q.attach(c,"dragover",function(e){if(r(e)){var n=qq.ie()&&qq.supportedFeatures.fileDrop?null:e.dataTransfer.effectAllowed;"move"===n||"linkMove"===n?e.dataTransfer.dropEffect="move":e.dataTransfer.dropEffect="copy",e.stopPropagation(),e.preventDefault()}}),q.attach(c,"dragenter",function(e){if(!o()){if(!r(e))return;u.onEnter(e)}}),q.attach(c,"dragleave",function(e){if(r(e)){u.onLeave(e);var n=document.elementFromPoint(e.clientX,e.clientY);qq(this).contains(n)||u.onLeaveNotDescendants(e)}}),q.attach(c,"drop",function(e){if(!o()){if(!r(e))return;e.preventDefault(),e.stopPropagation(),u.onDrop(e),i()}})}var u,c,s,l,q=new qq.DisposeSupport;u={element:null,onEnter:function(e){},onLeave:function(e){},onLeaveNotDescendants:function(e){},onDrop:function(e){}},qq.extend(u,e),c=u.element,t(),a(),qq.extend(this,{dropDisabled:function(e){return o(e)},dispose:function(){q.dispose()},getElement:function(){return c}})}}(window);
+//# sourceMappingURL=dnd.min.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/dnd.min.js.map b/libs/bower/bower_components/fine-uploader/dist/dnd.min.js.map
new file mode 100644
index 000000000000..d91c66e58db3
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/dnd.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/dnd.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","intArray","mimeString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","testSupportsFileInputElement","tempInput","supported","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","DragAndDrop","o","uploadDroppedFiles","files","uploadDropZone","filesAsArray","options","callbacks","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","entry","parseEntryPromise","file","fullPath","indexOfNameInFullPath","qqPath","droppedFiles","fileError","code","isDirectory","getFilesInDirectory","entries","entriesLeft","reader","accumEntries","existingPromise","dirReader","createReader","readEntries","newEntries","setTimeout","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","allowMultipleItems","dropError","getAsFile","pop","setupDropzone","dropArea","dropZone","UploadDropZone","HIDE_ZONES_EVENT_NAME","onEnter","classes","dropActive","stopPropagation","onLeaveNotDescendants","onDrop","disposeSupport","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","relatedTarget","x","y","setupDragDrop","dropZones","dropZoneElements","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","splice","targetEl","errorSpecifics","dragoverShouldBeCanceled","disableDropOutside","dropOutsideDisabled","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","isOrSetDropDisabled","isDisabled","preventDrop","triggerHidezonesEvent","triggerUsingOldApi","hideZonesEvent","createEvent","initEvent","CustomEvent","err","dispatchEvent","attachEvents","effect","onLeave","elementFromPoint","clientX","clientY"],"mappings":";CAAA,SAAUA,QCEV,GAAIC,IAAK,SAASC,GACd,YAEA,QACIC,KAAM,WAEF,MADAD,GAAQE,MAAMC,QAAU,OACjBC,MAIXC,OAAQ,SAASC,EAAMC,GAMnB,MALIP,GAAQQ,iBACRR,EAAQQ,iBAAiBF,EAAMC,GAAI,GAC5BP,EAAQS,aACfT,EAAQS,YAAY,KAAOH,EAAMC,GAE9B,WACHR,GAAGC,GAASU,OAAOJ,EAAMC,KAIjCG,OAAQ,SAASJ,EAAMC,GAMnB,MALIP,GAAQW,oBACRX,EAAQW,oBAAoBL,EAAMC,GAAI,GAC/BP,EAAQS,aACfT,EAAQY,YAAY,KAAON,EAAMC,GAE9BH,MAGXS,SAAU,SAASC,GAKf,QAAKA,IAKDd,IAAYc,IAIZd,EAAQa,SACDb,EAAQa,SAASC,MAGgC,EAA9CA,EAAWC,wBAAwBf,OAOrDgB,aAAc,SAASC,GAEnB,MADAA,GAASC,WAAWF,aAAahB,EAASiB,GACnCb,MAGXe,OAAQ,WAEJ,MADAnB,GAAQkB,WAAWE,YAAYpB,GACxBI,MAOXiB,IAAK,SAASC,GAEV,GAAqB,MAAjBtB,EAAQE,MACR,KAAM,IAAIH,IAAGwB,MAAM,6EAWvB,OAPsB,OAAlBD,EAAOE,SAC8B,gBAA1BxB,GAAQE,MAAMsB,SAAqD,mBAArBxB,GAAe,UACpEsB,EAAOG,OAAS,iBAAmBC,KAAKC,MAAM,IAAML,EAAOE,SAAW,KAG9EzB,GAAG6B,OAAO5B,EAAQE,MAAOoB,GAElBlB,MAGXyB,SAAU,SAASC,EAAMC,GACrB,GAAIC,GAAK,GAAIC,QAAO,QAAUH,EAAO,QACrC,OAAOE,GAAGE,KAAKlC,EAAQmC,eAAiBJ,IAAkBC,EAAGE,KAAKlC,EAAQkB,WAAWiB,aAGzFC,SAAU,SAASN,GAIf,MAHK/B,IAAGC,GAAS6B,SAASC,KACtB9B,EAAQmC,WAAa,IAAML,GAExB1B,MAGXiC,YAAa,SAASP,GAClB,GAAIE,GAAK,GAAIC,QAAO,QAAUH,EAAO,QAErC,OADA9B,GAAQmC,UAAYnC,EAAQmC,UAAUG,QAAQN,EAAI,KAAKM,QAAQ,aAAc,IACtElC,MAGXmC,WAAY,SAASJ,EAAWK,GAC5B,GAAIC,GACAC,IAEJ,OAAIF,IAASxC,EAAQ2C,cACV3C,EAAQ2C,cAAc,IAAMR,GAE9BnC,EAAQ4C,iBACN5C,EAAQ4C,iBAAiB,IAAMT,IAG1CM,EAAazC,EAAQ6C,qBAAqB,KAE1C9C,GAAG+C,KAAKL,EAAY,SAASM,EAAKC,GAC1BjD,GAAGiD,GAAKnB,SAASM,IACjBO,EAAOO,KAAKD,KAGbR,EAAQE,EAAO,GAAKA,IAG/BQ,gBAAiB,SAASf,GACtB,MAAOpC,IAAGC,GAASuC,WAAWJ,GAAW,IAG7CgB,SAAU,WAIN,IAHA,GAAIA,MACAC,EAAQpD,EAAQqD,WAEbD,GACoB,IAAnBA,EAAME,UACNH,EAASF,KAAKG,GAElBA,EAAQA,EAAMG,WAGlB,OAAOJ,IAGXK,QAAS,SAASC,GAGd,MAFAzD,GAAQ0D,UAAYD,EACpBzD,EAAQ2D,YAAcF,EACfrD,MAGXwD,UAAW,WACP,MAAO7D,IAAGC,GAASwD,QAAQ,KAK/BK,aAAc,SAASC,GACnB,GAAIC,EAEJ,OAAI/D,GAAQ6D,eAEH7D,EAAQ6D,aAAaC,IAKkC,MAArD,WAAaE,KAAKhE,EAAQiE,aAAaH,KAG9CC,EAAU/D,EAAQ8D,GAEFI,SAAZH,GAKiC,MAA9B,WAAaC,KAAKD,QAMxC,WACG,YAEAhE,IAAGoE,aAAe,SAASC,EAAQC,EAAMC,GACrC,MAAOvE,IAAGwE,cAAcH,EAAOI,UAAUH,EAAMC,KAGnDvE,GAAGwE,cAAgB,SAASE,GACxB,GAAIC,GAAaC,EAgBbC,EAAUC,EAfVC,EAAa,SAASC,EAAMV,GACxB,GAAIW,GAAcC,OAAOD,aACjBC,OAAOC,mBACPD,OAAOE,gBACPF,OAAOG,cACXC,EAAcL,GAAe,GAAIA,EAErC,OAAIK,IACAA,EAAYC,OAAOP,GACZM,EAAYE,QAAQlB,IAGpB,GAAImB,OAAMT,IAAQzE,KAAM+D,IAyB3C,OAlBIM,GADAF,EAAQgB,MAAM,KAAK,GAAGC,QAAQ,WAAa,EAC9BC,KAAKlB,EAAQgB,MAAM,KAAK,IAGxBG,UAAUnB,EAAQgB,MAAM,KAAK,IAI9CZ,EAAaJ,EAAQgB,MAAM,KAAK,GAC3BA,MAAM,KAAK,GACXA,MAAM,KAAK,GAGhBf,EAAc,GAAImB,aAAYlB,EAAWmB,QACzClB,EAAW,GAAImB,YAAWrB,GAC1B3E,GAAG+C,KAAK6B,EAAY,SAAS5B,EAAKiD,GAC9BpB,EAAS7B,GAAOiD,EAAUC,WAAW,KAGlCnB,EAAWJ,EAAaG,IAGnC9E,GAAGmG,IAAM,SAASC,EAASC,GACnBnB,OAAOoB,UACFD,GAAmB,SAAVA,EAKNnB,OAAOoB,QAAQD,GACfnB,OAAOoB,QAAQD,GAAOD,GAGtBlB,OAAOoB,QAAQH,IAAI,IAAME,EAAQ,KAAOD,GAR5ClB,OAAOoB,QAAQH,IAAIC,KAc/BpG,GAAGuG,SAAW,SAASC,GACnB,MAAOA,KAAaA,EAASjD,UAAyD,oBAA7CkD,OAAOC,UAAUC,SAASC,KAAKJ,IAG5ExG,GAAG6G,WAAa,SAASL,GACrB,MAA6B,kBAAf,IASlBxG,GAAG8G,QAAU,SAASC,GAClB,MAAiD,mBAA1CN,OAAOC,UAAUC,SAASC,KAAKG,IACjCA,GAAS7B,OAAOY,aAAeiB,EAAMC,QAAUD,EAAMC,OAAOC,cAAgBnB,aAIrF9F,GAAGkH,WAAa,SAASC,GACrB,MAAyD,kCAAlDV,OAAOC,UAAUC,SAASC,KAAKO,IAK1CnH,GAAGoH,WAAa,SAASC,GACrB,MAAyD,sBAAlDZ,OAAOC,UAAUC,SAASC,KAAKS,IAGjCA,EAAcC,MAAQD,EAAcE,WAG7CvH,GAAGwH,SAAW,SAASC,GACnB,MAAuD,oBAAhDhB,OAAOC,UAAUC,SAASC,KAAKa,IAG1CzH,GAAG0H,QAAU,SAASC,GAClB,MAAIC,QAAOlB,UAAUmB,KACVF,EAAOE,OAGXF,EAAOpF,QAAQ,aAAc,KAOxCvC,GAAG8H,OAAS,SAASC,GAEjB,GAAIC,GAAQC,MAAMvB,UAAUwB,MAAMtB,KAAKuB,UAAW,GAC9CC,EAASL,EACTM,EAAmBD,EAAOzC,QAAQ,KAetC,OAbA3F,IAAG+C,KAAKiF,EAAM,SAAShF,EAAKC,GACxB,GAAIqF,GAAYF,EAAOG,UAAU,EAAGF,GAChCG,EAAWJ,EAAOG,UAAUF,EAAmB,EAMnD,IAJAD,EAASE,EAAYrF,EAAMuF,EAC3BH,EAAmBD,EAAOzC,QAAQ,KAAM0C,EAAmBpF,EAAI8C,QAG3DsC,EAAmB,EACnB,OAAO,IAIRD,GAGXpI,GAAGyI,OAAS,SAASC,GACjB,MAAOxD,QAAOyD,MAAsD,kBAA9ClC,OAAOC,UAAUC,SAASC,KAAK8B,IAGzD1I,GAAG4I,WAAa,SAASC,GACrB,MAAO3D,QAAO4D,UAA8D,sBAAlDrC,OAAOC,UAAUC,SAASC,KAAKiC,IAG7D7I,GAAG+I,cAAgB,SAASC,GACxB,MAAOhJ,IAAGyI,OAAOO,IAAqBhJ,GAAGiJ,QAAQD,IAGrDhJ,GAAGiJ,QAAU,SAASC,EAAYC,GAC9B,GAAIC,GAAe,SAAS7I,GACxB,GAAI8I,GAAiB9I,EAAK+I,aAE1B,OAAIH,GAC0B,SAAnBE,EAGe,SAAnBA,EAGX,UAAInE,OAAOqE,kBAC4C,8BAA/C9C,OAAOC,UAAUC,SAASC,KAAKsC,IAC3BA,EAAW3I,MAAQ6I,EAAaF,EAAW3I,WAKnD2I,EAAWM,SAC8B,UAArCN,EAAWM,QAAQF,eACfJ,EAAW3I,MAAQ6I,EAAaF,EAAW3I,QAS3DP,GAAGyJ,OAAS,SAASC,GACjB,GAAIxE,OAAOO,MAAsD,kBAA9CgB,OAAOC,UAAUC,SAASC,KAAK8C,GAC9C,OAAO,GAIf1J,GAAG2J,qBAAuB,WACtB,GAAIC,GAAQC,SAASC,cAAc,QAGnC,OAFAF,GAAMrJ,KAAO,OAGU4D,SAAnByF,EAAMG,UACc,mBAATpB,OACa,mBAAbqB,WACoC,mBAAnChK,IAAGiK,oBAAqBC,QAI5ClK,GAAGiK,kBAAoB,WACnB,GAAI/E,OAAOiF,eACP,MAAO,IAAIA,eAGf,KACI,MAAO,IAAIC,eAAc,sBAE7B,MAAOC,GAEH,MADArK,IAAGmG,IAAI,wCAAyC,SACzC,OAIfnG,GAAGsK,sBAAwB,SAASC,GAChC,MAAOA,GAAaC,OAChBD,EAAaC,MAAMzE,OAAS,GAC5BwE,EAAaC,MAAM,GAAGC,kBAG9BzK,GAAG0K,wBAA0B,WACzB,OAAQ1K,GAAG2K,gBACP3K,GAAG2J,yBACuBxF,SAAzBwE,KAAKjC,UAAUwB,OAAsD/D,SAA/BwE,KAAKjC,UAAUkE,aAAyDzG,SAA5BwE,KAAKjC,UAAUmE,WAG1G7K,GAAG8K,UAAY,SAASC,EAAYC,EAAOC,GACvC,GAAIC,GAASH,EAAW7C,OAAS6C,EAAWF,UAAYE,EAAWH,WAEnE,OAAOM,GAAOtE,KAAKmE,EAAYC,EAAOC,IAG1CjL,GAAGmL,iBAAmB,SAASnE,GAC3B,GAAIoE,GAAa,GACbC,EAAQ,GAAIrF,YAAWgB,EAY3B,OAVAhH,IAAG+C,KAAKsI,EAAO,SAASrI,EAAKsI,GACzB,GAAIC,GAAeD,EAAI3E,SAAS,GAE5B4E,GAAaxF,OAAS,IACtBwF,EAAe,IAAMA,GAGzBH,GAAcG,IAGXH,GAGXpL,GAAGwL,cAAgB,SAASC,EAAMC,EAAa3F,GAC3C,GAAI4F,GAAc3L,GAAG8K,UAAUW,EAAMC,EAAaA,EAAc3F,GAC5D6F,EAAa,GAAIC,YACjBC,EAAU,GAAI9L,IAAG+L,OAUrB,OARAH,GAAWI,OAAS,WAChBF,EAAQG,QAAQjM,GAAGmL,iBAAiBS,EAAWjJ,UAGnDiJ,EAAWM,QAAUJ,EAAQK,QAE7BP,EAAWQ,kBAAkBT,GAEtBG,GAGX9L,GAAG6B,OAAS,SAASY,EAAO4J,EAAQC,GAahC,MAZAtM,IAAG+C,KAAKsJ,EAAQ,SAASE,EAAMtJ,GACvBqJ,GAAgBtM,GAAGuG,SAAStD,IACRkB,SAAhB1B,EAAM8J,KACN9J,EAAM8J,OAEVvM,GAAG6B,OAAOY,EAAM8J,GAAOtJ,GAAK,IAG5BR,EAAM8J,GAAQtJ,IAIfR,GAaXzC,GAAGwM,SAAW,SAASC,EAAQC,GAC3B,GAAIC,MACAC,EAASF,EAASC,EAUtB,OARA3M,IAAG+C,KAAK6J,EAAQ,SAASC,EAAaC,GACN3I,SAAxBsI,EAAOI,KACPF,EAAOE,GAAeJ,EAAOI,IAGjCJ,EAAOI,GAAeC,IAGnBL,GAMXzM,GAAG2F,QAAU,SAASoH,EAAKC,EAAKC,GAC5B,GAAIF,EAAIpH,QACJ,MAAOoH,GAAIpH,QAAQqH,EAAKC,EAG5BA,GAAOA,GAAQ,CACf,IAAIC,GAAMH,EAAIhH,MAMd,KAJIkH,EAAO,IACPA,GAAQC,GAGLD,EAAOC,EAAKD,GAAQ,EACvB,GAAIF,EAAII,eAAeF,IAASF,EAAIE,KAAUD,EAC1C,MAAOC,EAGf,QAAO,GAIXjN,GAAGoN,YAAc,WACb,MAAO,uCAAuC7K,QAAQ,QAAS,SAAS8K,GAEpE,GAAIC,GAAoB,GAAhB3L,KAAK4L,SAAgB,EAAGC,EAAS,KAALH,EAAWC,EAAS,EAAJA,EAAU,CAC9D,OAAOE,GAAE7G,SAAS,OAM1B3G,GAAGyN,GAAK,WACJ,MAAOC,WAAUC,UAAUhI,QAAQ,WAAY,GAC3C+H,UAAUC,UAAUhI,QAAQ,cAAe,GAGnD3F,GAAG4N,IAAM,WACL,MAAOF,WAAUC,UAAUhI,QAAQ,aAAc,GAGrD3F,GAAG6N,IAAM,WACL,MAAOH,WAAUC,UAAUhI,QAAQ,aAAc,GAGrD3F,GAAG8N,KAAO,WACN,MAAOJ,WAAUC,UAAUhI,QAAQ,cAAe,GAGtD3F,GAAG+N,KAAO,WACN,MAAO/N,IAAGyN,MAAQC,UAAUC,UAAUhI,QAAQ,YAAa,GAG/D3F,GAAGgO,KAAO,WACN,MAAON,WAAUC,UAAUhI,QAAQ,SAAW,GAGlD3F,GAAGiO,OAAS,WACR,MAA4B9J,UAArBuJ,UAAUQ,QAAwBR,UAAUQ,OAAOvI,QAAQ,YAAa,GAGnF3F,GAAGmO,OAAS,WACR,MAA4BhK,UAArBuJ,UAAUQ,QAAwBR,UAAUQ,OAAOvI,QAAQ,aAAc,GAGpF3F,GAAGoO,MAAQ,WACP,MAA4BjK,UAArBuJ,UAAUQ,QAAwBR,UAAUQ,OAAOvI,QAAQ,YAAa,GAGnF3F,GAAGqO,QAAU,WACT,OAASrO,GAAGgO,SAAWhO,GAAG+N,QAAUL,UAAUC,UAAUhI,QAAQ,cAAe,GAA2BxB,SAArBuJ,UAAUQ,QAA6C,KAArBR,UAAUQ,QAGrIlO,GAAGsO,QAAU,WACT,MAA8B,UAAvBZ,UAAUa,UAGrBvO,GAAGwO,QAAU,WACT,MAAOd,WAAUC,UAAUrE,cAAc3D,QAAQ,cAAe,GAKpE3F,GAAG2K,aAAe,WACd,MAAO3K,IAAGwO,WAAad,UAAUC,UAAUrE,cAAc3D,QAAQ,UAAY,GAGjF3F,GAAGyO,KAAO,WACN,MAAOzO,IAAG0O,OAAShB,UAAUC,UAAUhI,QAAQ,aAAc,GAGjE3F,GAAG2O,KAAO,WACN,MAAO3O,IAAG0O,OAAShB,UAAUC,UAAUhI,QAAQ,aAAc,GAGjE3F,GAAG4O,KAAO,WACN,MAAO5O,IAAG0O,OAAShB,UAAUC,UAAUhI,QAAQ,aAAc,GAIjE3F,GAAG6O,OAAS,WACR,MAAO7O,IAAG0O,OAAShB,UAAUC,UAAUhI,QAAQ,eAAgB,GAGnE3F,GAAG0O,IAAM,WAEL,MAAOhB,WAAUC,UAAUhI,QAAQ,WAAY,GACxC+H,UAAUC,UAAUhI,QAAQ,WAAY,GACxC+H,UAAUC,UAAUhI,QAAQ,aAAc,GAGrD3F,GAAG8O,UAAY,WACX,MAAO9O,IAAG0O,OAAShB,UAAUC,UAAUhI,QAAQ,YAAa,GAGhE3F,GAAG+O,UAAY,WACX,MAAO/O,IAAG0O,QAAU1O,GAAG8O,aAAepB,UAAUC,UAAUhI,QAAQ,aAAc,GAGpF3F,GAAGgP,iBAAmB,WAClB,MAAOhP,IAAG0O,QAAU1O,GAAG8O,cAAgB9O,GAAG+O,aAM9C/O,GAAGiP,eAAiB,SAASC,GACrBA,EAAED,eACFC,EAAED,iBAEFC,EAAEC,aAAc,GAQxBnP,GAAGoP,UAAa,WACZ,GAAIC,GAAMxF,SAASC,cAAc,MACjC,OAAO,UAASwF,GACZD,EAAIE,UAAYD,CAChB,IAAIrP,GAAUoP,EAAI/L,UAElB,OADA+L,GAAIhO,YAAYpB,GACTA,MAKfD,GAAG+C,KAAO,SAASyM,EAAcC,GAC7B,GAAIC,GAAYC,CAEhB,IAAIH,EAEA,GAAItK,OAAO0K,SAAWJ,EAAavI,cAAgB/B,OAAO0K,QACtD,IAAKF,EAAa,EAAGA,EAAaF,EAAazJ,SAC3C4J,EAASF,EAASD,EAAaK,IAAIH,GAAaF,EAAaM,QAAQN,EAAaK,IAAIH,KAClFC,KAAW,GAFoCD,SAStD,IAAI1P,GAAG8G,QAAQ0I,IAAiBxP,GAAGkH,WAAWsI,IAAiBxP,GAAGoH,WAAWoI,GAC9E,IAAKE,EAAa,EAAGA,EAAaF,EAAazJ,SAC3C4J,EAASF,EAASC,EAAYF,EAAaE,IACvCC,KAAW,GAFoCD,SAOtD,IAAI1P,GAAGwH,SAASgI,GACjB,IAAKE,EAAa,EAAGA,EAAaF,EAAazJ,SAC3C4J,EAASF,EAASC,EAAYF,EAAaO,OAAOL,IAC9CC,KAAW,GAFoCD,SAQvD,KAAKA,IAAcF,GACf,GAAI/I,OAAOC,UAAUyG,eAAevG,KAAK4I,EAAcE,KACnDC,EAASF,EAASC,EAAYF,EAAaE,IACvCC,KAAW,GACX,OASxB3P,GAAGgQ,KAAO,SAASC,EAASC,GACxB,GAAIlQ,GAAG6G,WAAWoJ,GAAU,CACxB,GAAIjI,GAAQC,MAAMvB,UAAUwB,MAAMtB,KAAKuB,UAAW,EAElD,OAAO,YACH,GAAIgI,GAAUnQ,GAAG6B,UAAWmG,EAI5B,OAHIG,WAAUpC,SACVoK,EAAUA,EAAQC,OAAOnI,MAAMvB,UAAUwB,MAAMtB,KAAKuB,aAEjD8H,EAAQI,MAAMH,EAASC,IAItC,KAAM,IAAI3O,OAAM,wCAmBpBxB,GAAGsQ,QAAU,SAASC,EAAKC,EAAMC,GAE7B,GAAIC,MACAC,EAAS,IACTC,EAAM,SAASC,EAASC,GACpB,GAAIC,GAAWP,EACR,QAAQrO,KAAKqO,GACdA,EACAA,EAAO,IAAMM,EAAI,IACjBA,CACY,eAAbC,GAAoC,cAAND,GAC/BJ,EAAWxN,KACa,gBAAZ2N,GACF7Q,GAAGsQ,QAAQO,EAASE,GAAU,GACe,sBAA5CtK,OAAOC,UAAUC,SAASC,KAAKiK,GAChCG,mBAAmBD,GAAY,IAAMC,mBAAmBH,KACxDG,mBAAmBD,GAAY,IAAMC,mBAAmBH,IAqB9E,QAhBKJ,GAAcD,GACfG,EAAU,KAAKxO,KAAKqO,GAAU,MAAMrO,KAAKqO,GAAS,GAAK,IAAM,IAC7DE,EAAWxN,KAAKsN,GAChBE,EAAWxN,KAAKlD,GAAGsQ,QAAQC,KACqB,mBAAxC9J,OAAOC,UAAUC,SAASC,KAAK2J,IAA8C,mBAARA,GAC7EvQ,GAAG+C,KAAKwN,EAAK,SAASvN,EAAKC,GACvB2N,EAAI3N,EAAKD,KAEU,mBAARuN,IAAiC,OAARA,GAAiC,gBAARA,GACjEvQ,GAAG+C,KAAKwN,EAAK,SAAShE,EAAMtJ,GACxB2N,EAAI3N,EAAKsJ,KAGbmE,EAAWxN,KAAK8N,mBAAmBR,GAAQ,IAAMQ,mBAAmBT,IAGpEC,EACOE,EAAWO,KAAKN,GAEhBD,EAAWO,KAAKN,GAClBpO,QAAQ,KAAM,IACdA,QAAQ,OAAQ,MAI7BvC,GAAGkR,aAAe,SAASX,EAAKY,EAAUC,GAmBtC,MAlBKD,KACDA,EAAW,GAAInH,WAGnBhK,GAAG+C,KAAKwN,EAAK,SAASV,EAAK5M,GACvB4M,EAAMuB,EAAeA,EAAe,IAAMvB,EAAM,IAAMA,EAElD7P,GAAGuG,SAAStD,GACZjD,GAAGkR,aAAajO,EAAKkO,EAAUtB,GAE1B7P,GAAG6G,WAAW5D,GACnBkO,EAAS5L,OAAOsK,EAAK5M,KAGrBkO,EAAS5L,OAAOsK,EAAK5M,KAItBkO,GAGXnR,GAAGqR,WAAa,SAASd,EAAKe,GAC1B,GAAI1H,EAeJ,OAbK0H,KACDA,EAAOzH,SAASC,cAAc,SAGlC9J,GAAGkR,aAAaX,GACZhL,OAAQ,SAASsK,EAAK5M,GAClB2G,EAAQC,SAASC,cAAc,SAC/BF,EAAM2H,aAAa,OAAQ1B,GAC3BjG,EAAM2H,aAAa,QAAStO,GAC5BqO,EAAKE,YAAY5H,MAIlB0H,GAOXtR,GAAGyR,UAAY,SAASC,MAEpB,MAAIxM,QAAOyM,MAAQ3R,GAAG6G,WAAW8K,KAAKC,OAC3BD,KAAKC,MAAMF,MAEXG,KAAK,IAAMH,KAAO,MAUjC1R,GAAG8R,aAAe,SAASC,GACvB,GAAIC,GAASD,EAASE,YAAY,KAAO,CAEzC,IAAID,EAAS,EACT,MAAOD,GAASG,OAAOF,EAAQD,EAAShM,OAASiM,IAIzDhS,GAAGmS,YAAc,SAASC,GAGtB,MAAIpS,IAAGiJ,QAAQmJ,GAEJA,EAAgBrL,MAAMxE,QAAQ,YAAa,IAE7CvC,GAAGyI,OAAO2J,IACkB,OAA7BA,EAAgBC,UAAkDlO,SAA7BiO,EAAgBC,SAC9CD,EAAgBC,SAIxBD,EAAgBrQ,MAM3B/B,GAAGsS,eAAiB,WAChB,GAAIC,KAEJ,QAEIC,QAAS,WACL,GAAIC,EACJ,GACIA,GAAWF,EAAUG,QACjBD,GACAA,UAGDA,IAIXnS,OAAQ,WACJ,GAAI0H,GAAOG,SAEX9H,MAAKsS,YAAY3S,GAAGgI,EAAK,IAAI1H,OAAO+P,MAAMhQ,KAAM4H,MAAMvB,UAAUwB,MAAMtB,KAAKuB,UAAW,MAI1FwK,YAAa,SAASC,GAClBL,EAAUrP,KAAK0P,SCt2B9B,WACG,YACsB,mBAAXC,SAAyBA,OAAOC,IACvCD,OAAO,WACH,MAAO7S,MAGY,mBAAX+S,SAA0BA,OAAOC,QAC7CD,OAAOC,QAAUhT,GAGjBD,OAAOC,GAAKA,MCXpBA,GAAGiT,QAAU,SCAbjT,GAAGkT,kBAAqB,WACpB,YAkBA,SAASC,KACL,GACIC,GADAC,GAAY,CAGhB,KACID,EAAYvJ,SAASC,cAAc,SACnCsJ,EAAU7S,KAAO,OACjBP,GAAGoT,GAAWlT,OAEVkT,EAAUE,WACVD,GAAY,GAGpB,MAAOE,GACHF,GAAY,EAGhB,MAAOA,GAIX,QAASG,KACL,OAAQxT,GAAGmO,UAAYnO,GAAGoO,UAC+CjK,SAArEuJ,UAAUC,UAAU8F,MAAM,uCAIlC,QAASC,KACL,OAAQ1T,GAAGmO,UAAYnO,GAAGoO,UAC+CjK,SAArEuJ,UAAUC,UAAU8F,MAAM,uCAIlC,QAASE,KACL,GAAIzO,OAAOiF,eAAgB,CACvB,GAAIyJ,GAAM5T,GAAGiK,mBAGb,OAA+B9F,UAAxByP,EAAIC,gBAGf,OAAO,EAIX,QAASC,KACL,MAAiC3P,UAA1Be,OAAO6O,eAKlB,QAASC,KACL,QAAIL,KAIGG,IAGX,QAASG,KAEL,MAA2D9P,UAApD0F,SAASC,cAAc,SAASoK,gBAG3C,QAASC,KACL,IACI,QAASjP,OAAOkP,cAEZpU,GAAG6G,WAAW3B,OAAOkP,aAAaC,SAE1C,MAAOhK,GAEH,OAAO,GAIf,QAASiK,KACL,GAAIC,GAAO1K,SAASC,cAAc,OAElC,QAAQ,aAAeyK,IAAS,eAAiBA,IAAQ,UAAYA,MAChEvU,GAAGwO,YAAcxO,GAAG0O,MAhG7B,GAAI8F,GACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,CAwHJ,OAnCAd,GAAoBrB,IAEpBwB,EAA4BH,GAAqBxU,GAAG2J,uBAEpD8K,EAAyBE,IAA8B3U,GAAG2K,eAE1D+J,EAAmBC,GAA6BL,IAEhDM,EAAqBF,GAAoBlB,IAEzCqB,EAAmBF,GAA6B3U,GAAG0K,0BAEnDoK,EAAiBH,GAA6BE,GAAoBV,IAElEY,EAAyBJ,GAA6BjB,IAEtDsB,EAAqBR,IAA6CrQ,SAAvBe,OAAOqQ,aAA6BZ,GAE/EO,EAA4BvB,IAE5BsB,EAAwBnB,IAExBqB,EAAyBnB,IAEzBoB,EAA0BnB,IAE1BoB,EAAwBV,GAAmDxQ,SAAtBe,OAAO2G,WAE5DyJ,EAA0B,WACtB,QAAIX,KACQ3U,GAAG2K,iBAAmB3K,GAAG8O,iBAMrC0G,cAAeb,EACfc,cAAehB,EACfiB,iBAAkBf,EAClBgB,SAAUd,EACVe,eAAgBT,EAChBU,kBAAmBZ,EACnBa,kBAAmBZ,EACnBa,gBAAiB7Q,OAAO8Q,kBACxBC,SAAUvB,EACVwB,WAAYtB,EACZuB,gBAAiBf,EACjBgB,cAAef,EACfgB,gBAAiBhB,EACjBiB,mBAAoB3B,EACpB4B,MAAO1B,EACP2B,YAAalB,EACbmB,OAAQ3B,EACR4B,QAASrB,GAAyBZ,EAClCkC,aAAc3W,GAAGiO,SACjB2I,0BAA2B5W,GAAG0O,MAC9BmI,UAAWrC,EACXsC,WAAY9B,EACZ+B,oBAAqBpC,EACrBqC,mBAAoBrC,EACpBsC,eAAgBlC,MChKxB/U,GAAGkX,iBAAmB,SAASC,GAC3B,YACA,UAAUA,GAAgBA,EAAaC,MAAQpX,GAAG6G,WAAWsQ,EAAaC,QAG9EpX,GAAG+L,QAAU,WACT,YAEA,IAAIsL,GAAaC,EACbC,KACAC,KACAC,KACAC,EAAQ,CAEZ1X,IAAG6B,OAAOxB,MACN+W,KAAM,SAASO,EAAWC,GAgBtB,MAfc,KAAVF,GACIC,GACAJ,EAAiBrU,KAAKyU,GAEtBC,GACAJ,EAAiBtU,KAAK0U,IAGrBF,KAAU,EACfE,GAAaA,EAAUvH,MAAM,KAAMiH,GAE9BK,GACLA,EAAUtH,MAAM,KAAMgH,GAGnBhX,MAGXwX,KAAM,SAASpI,GAQX,MAPc,KAAViI,EACAD,EAAcvU,KAAKuM,GAGnBA,EAASY,MAAM,KAAsBlM,SAAhBmT,EAA4BD,EAAcC,GAG5DjX,MAGX4L,QAAS,WAgBL,MAfAyL,GAAQ,EACRL,EAAclP,UAEVoP,EAAiBxR,QACjB/F,GAAG+C,KAAKwU,EAAkB,SAASvU,EAAKyM,GACpCA,EAASY,MAAM,KAAMgH,KAIzBI,EAAc1R,QACd/F,GAAG+C,KAAK0U,EAAe,SAASzU,EAAKyM,GACjCA,EAASY,MAAM,KAAMgH,KAItBhX,MAGX8L,QAAS,WAgBL,MAfAuL,IAAQ,EACRJ,EAAcnP,UAEVqP,EAAiBzR,QACjB/F,GAAG+C,KAAKyU,EAAkB,SAASxU,EAAKyM,GACpCA,EAASY,MAAM,KAAMiH,KAIzBG,EAAc1R,QACd/F,GAAG+C,KAAK0U,EAAe,SAASzU,EAAKyM,GACjCA,EAASY,MAAM,KAAMiH,KAItBjX,SClFnBL,GAAG8X,YAAc,SAASC,GACtB,YAoBA,SAASC,GAAmBC,EAAOC,GAE/B,GAAIC,GAAelQ,MAAMvB,UAAUwB,MAAMtB,KAAKqR,EAE9CG,GAAQC,UAAUC,QAAQ,WAAaL,EAAMlS,OAAS,mBACtDmS,EAAeK,cAAa,GAC5BH,EAAQC,UAAUG,+BAA+BL,EAAcD,EAAeO,cAGlF,QAASC,GAAiBC,GACtB,GAAIC,GAAoB,GAAI5Y,IAAG+L,OAoD/B,OAlDI4M,GAAMlQ,OACNkQ,EAAME,KAAK,SAASA,GAChB,GAAI9W,GAAO4W,EAAM5W,KACb+W,EAAWH,EAAMG,SACjBC,EAAwBD,EAASnT,QAAQ5D,EAG7C+W,GAAWA,EAAS5G,OAAO,EAAG6G,GAGH,MAAvBD,EAAS/I,OAAO,KAChB+I,EAAWA,EAAS5G,OAAO,IAG/B2G,EAAKG,OAASF,EACdG,EAAa/V,KAAK2V,GAClBD,EAAkB3M,WAEtB,SAASiN,GACLd,EAAQC,UAAUC,QAAQ,oBAAsBK,EAAMG,SAAW,sBAAwBI,EAAUC,KAAO,IAAK,SAC/GP,EAAkBzM,YAGjBwM,EAAMS,aACXC,EAAoBV,GAAOvB,KACvB,SAAwBkC,GACpB,GAAIC,GAAcD,EAAQvT,MAE1B/F,IAAG+C,KAAKuW,EAAS,SAAStW,EAAK2V,GAC3BD,EAAiBC,GAAOd,KAAK,WACzB0B,GAAe,EAEK,IAAhBA,GACAX,EAAkB3M,cAKzBqN,EAAQvT,QACT6S,EAAkB3M,WAI1B,SAAqBiN,GACjBd,EAAQC,UAAUC,QAAQ,oBAAsBK,EAAMG,SAAW,sBAAwBI,EAAUC,KAAO,IAAK,SAC/GP,EAAkBzM,YAKvByM,EAIX,QAASS,GAAoBV,EAAOa,EAAQC,EAAcC,GACtD,GAAI5N,GAAU4N,GAAmB,GAAI1Z,IAAG+L,QACpC4N,EAAYH,GAAUb,EAAMiB,cAmBhC,OAjBAD,GAAUE,YACN,SAAqBP,GACjB,GAAIQ,GAAaL,EAAeA,EAAarJ,OAAOkJ,GAAWA,CAE3DA,GAAQvT,OACRgU,WAAW,WACPV,EAAoBV,EAAOgB,EAAWG,EAAYhO,IACnD,GAGHA,EAAQG,QAAQ6N,IAIxBhO,EAAQK,SAGLL,EAGX,QAASkO,GAAmBzP,EAAc2N,GACtC,GAAI+B,MACAC,EAA4B,GAAIla,IAAG+L,OA4CvC,OA1CAqM,GAAQC,UAAU8B,yBAClBjC,EAAeK,cAAa,GAExBhO,EAAa0N,MAAMlS,OAAS,IAAMqS,EAAQgC,oBAC1ChC,EAAQC,UAAUG,mCAClBJ,EAAQC,UAAUgC,UAAU,oBAAqB,IACjDnC,EAAeK,cAAa,GAC5B2B,EAA0B/N,YAG1B8M,KAEIjZ,GAAGsK,sBAAsBC,GACzBvK,GAAG+C,KAAKwH,EAAaC,MAAO,SAASxH,EAAKsE,GACtC,GAAIqR,GAAQrR,EAAKmD,kBAEbkO,KAEIA,EAAMlQ,OACNwQ,EAAa/V,KAAKoE,EAAKgT,aAIvBL,EAAsB/W,KAAKwV,EAAiBC,GAAOd,KAAK,WACpDoC,EAAsBM,MACe,IAAjCN,EAAsBlU,QACtBmU,EAA0BjO,gBAQ9CgN,EAAe1O,EAAa0N,MAGK,IAAjCgC,EAAsBlU,QACtBmU,EAA0BjO,WAI3BiO,EAGX,QAASM,GAAcC,GACnB,GAAIC,GAAW,GAAI1a,IAAG2a,gBAClBC,sBAAuBA,EACvB3a,QAASwa,EACTI,QAAS,SAAS3L,GACdlP,GAAGya,GAAUpY,SAAS+V,EAAQ0C,QAAQC,YACtC7L,EAAE8L,mBAENC,sBAAuB,SAAS/L,GAC5BlP,GAAGya,GAAUnY,YAAY8V,EAAQ0C,QAAQC,aAE7CG,OAAQ,SAAShM,GACb8K,EAAmB9K,EAAE3E,aAAcmQ,GAAUtD,KACzC,WACIY,EAAmBiB,EAAcyB,IAErC,WACItC,EAAQC,UAAUC,QAAQ,sEAAuE,aAcjH,OARA6C,GAAexI,YAAY,WACvB+H,EAASlI,YAGbxS,GAAGya,GAAU3W,aAAasX,IAA2Bpb,GAAGya,GAAUva,OAElEmb,EAAgBnY,KAAKwX,GAEdA,EAGX,QAASY,GAAWC,GAChB,GAAIC,EASJ,OAPAxb,IAAG+C,KAAKwY,EAAUhR,aAAakR,MAAO,SAAS5L,EAAK5M,GAChD,GAAY,UAARA,EAEA,MADAuY,IAAW,GACJ,IAIRA,EAWX,QAASE,GAAmBxM,GACxB,MAAIlP,IAAGqO,WACKa,EAAEyM,cAGV3b,GAAGiO,SACIiB,EAAE0M,EAAI,GAAK1M,EAAE2M,EAAI,EAGb,IAAR3M,EAAE0M,GAAmB,IAAR1M,EAAE2M,EAG1B,QAASC,KACL,GAAIC,GAAY3D,EAAQ4D,iBAEpBC,EAAqB,WACjBlC,WAAW,WACP/Z,GAAG+C,KAAKgZ,EAAW,SAAS/Y,EAAK0X,GAC7B1a,GAAG0a,GAAU5W,aAAasX,IAA2Bpb,GAAG0a,GAAUxa,OAClEF,GAAG0a,GAAUpY,YAAY8V,EAAQ0C,QAAQC,eAE9C,IAGX/a,IAAG+C,KAAKgZ,EAAW,SAAS/Y,EAAK0X,GAC7B,GAAIxC,GAAiBsC,EAAcE,EAG/BqB,GAAUhW,QAAU/F,GAAGkT,kBAAkB+C,UACzCkF,EAAe7a,OAAOuJ,SAAU,YAAa,SAASqF,IAC7CgJ,EAAeK,gBAAkB+C,EAAWpM,IAC7ClP,GAAG+C,KAAKgZ,EAAW,SAAS/Y,EAAK0X,GAGzBA,YAAoBwB,cACpBlc,GAAG0a,GAAU5W,aAAasX,IAE1Bpb,GAAG0a,GAAUpZ,KAAKlB,QAAS,gBAQnD+a,EAAe7a,OAAOuJ,SAAU,YAAa,SAASqF,GAC9CwM,EAAmBxM,IACnB+M,MAORd,EAAe7a,OAAON,GAAG6J,UAAUzG,WAAW,GAAI,aAAc,SAAS8L,GACrE+M,MAGJd,EAAe7a,OAAOuJ,SAAU,OAAQ,SAASqF,GAC7CA,EAAED,iBACFgN,MAGJd,EAAe7a,OAAOuJ,SAAU+Q,EAAuBqB,GAnR3D,GAAI7D,GACAwC,EAAwB,eACxBQ,EAAyB,mBACzBC,KACApC,KACAkC,EAAiB,GAAInb,IAAGsS,cAE5B8F,IACI4D,oBACA5B,oBAAoB,EACpBU,SACIC,WAAY,MAEhB1C,UAAW,GAAIrY,IAAG8X,YAAYO,WAGlCrY,GAAG6B,OAAOuW,EAASL,GAAG,GAsQtB+D,IAEA9b,GAAG6B,OAAOxB,MACN8b,mBAAoB,SAASlc,GACzBmY,EAAQ4D,iBAAiB9Y,KAAKjD,GAC9Bua,EAAcva,IAGlBmc,eAAgB,SAASnc,GACrB,GAAI6Q,GACAuL,EAAMjE,EAAQ4D,gBAElB,KAAKlL,IAAKuL,GACN,GAAIA,EAAIvL,KAAO7Q,EACX,MAAOoc,GAAIC,OAAOxL,EAAG,IAKjC0B,QAAS,WACL2I,EAAe3I,UACfxS,GAAG+C,KAAKsY,EAAiB,SAASrY,EAAK0X,GACnCA,EAASlI,gBAMzBxS,GAAG8X,YAAYO,UAAY,WACvB,YAEA,QACI8B,uBAAwB,aACxB3B,+BAAgC,SAASP,EAAOsE,KAChDlC,UAAW,SAASlB,EAAMqD,GACtBxc,GAAGmG,IAAI,2BAA6BgT,EAAO,2BAA6BqD,EAAiB,IAAK,UAElGlE,QAAS,SAASlS,EAASC,GACvBrG,GAAGmG,IAAIC,EAASC,MAK5BrG,GAAG2a,eAAiB,SAAS5C,GACzB,YAiBA,SAAS0E,KACL,MAAOzc,IAAGiO,UAAajO,GAAGqO,WAAarO,GAAGsO,UAG9C,QAASoO,GAAmBxN,GAEnByN,IAGGF,EACAtB,EAAe7a,OAAOuJ,SAAU,WAAY,SAASqF,GACjDA,EAAED,mBAGNkM,EAAe7a,OAAOuJ,SAAU,WAAY,SAASqF,GAC7CA,EAAE3E,eACF2E,EAAE3E,aAAaqS,WAAa,OAC5B1N,EAAED,oBAKd0N,GAAsB,GAI9B,QAASE,GAAgB3N,GAGrB,IAAKlP,GAAGkT,kBAAkB+C,SACtB,OAAO,CAGX,IAAI6G,GAAYC,EAAK7N,EAAE3E,aAEvByS,EAAWhd,GAAGiO,QAQd,OADA6O,MAAa9c,GAAGyN,OAAQzN,GAAGkT,kBAAkB+C,WAAuC,SAArB8G,EAAGE,cAC3DF,GAAMD,IAAeC,EAAG9E,QAAW+E,GAAYD,EAAGtB,MAAM3a,UAAYic,EAAGtB,MAAM3a,SAAS,UAGjG,QAASoc,GAAoBC,GAIzB,MAHmBhZ,UAAfgZ,IACAC,EAAcD,GAEXC,EAGX,QAASC,KAGL,QAASC,KACLC,EAAiB1T,SAAS2T,YAAY,SACtCD,EAAeE,UAAUrF,EAAQwC,uBAAuB,GAAM,GAJlE,GAAI2C,EAOJ,IAAIrY,OAAOwY,YACP,IACIH,EAAiB,GAAIG,aAAYtF,EAAQwC,uBAE7C,MAAO+C,GACHL,QAIJA,IAGJzT,UAAS+T,cAAcL,GAG3B,QAASM,KACL1C,EAAe7a,OAAOL,EAAS,WAAY,SAASiP,GAChD,GAAK2N,EAAgB3N,GAArB,CAMA,GAAI4O,GAAS9d,GAAGyN,MAAQzN,GAAGkT,kBAAkB+C,SAAW,KAAO/G,EAAE3E,aAAa0S,aAC/D,UAAXa,GAAgC,aAAXA,EACrB5O,EAAE3E,aAAaqS,WAAa,OAE5B1N,EAAE3E,aAAaqS,WAAa,OAGhC1N,EAAE8L,kBACF9L,EAAED,oBAGNkM,EAAe7a,OAAOL,EAAS,YAAa,SAASiP,GACjD,IAAKgO,IAAuB,CACxB,IAAKL,EAAgB3N,GACjB,MAEJkJ,GAAQyC,QAAQ3L,MAIxBiM,EAAe7a,OAAOL,EAAS,YAAa,SAASiP,GACjD,GAAK2N,EAAgB3N,GAArB,CAIAkJ,EAAQ2F,QAAQ7O,EAEhB,IAAIyM,GAAgB9R,SAASmU,iBAAiB9O,EAAE+O,QAAS/O,EAAEgP,QAEvDle,IAAGK,MAAMS,SAAS6a,IAItBvD,EAAQ6C,sBAAsB/L,MAGlCiM,EAAe7a,OAAOL,EAAS,OAAQ,SAASiP,GAC5C,IAAKgO,IAAuB,CACxB,IAAKL,EAAgB3N,GACjB,MAGJA,GAAED,iBACFC,EAAE8L,kBACF5C,EAAQ8C,OAAOhM,GAEfmO,OAjJZ,GACIjF,GAASnY,EAASmd,EAAaT,EAD/BxB,EAAiB,GAAInb,IAAGsS,cAG5B8F,IACInY,QAAS,KACT4a,QAAS,SAAS3L,KAClB6O,QAAS,SAAS7O,KAElB+L,sBAAuB,SAAS/L,KAChCgM,OAAQ,SAAShM,MAGrBlP,GAAG6B,OAAOuW,EAASL,GACnB9X,EAAUmY,EAAQnY,QAyIlByc,IACAmB,IAEA7d,GAAG6B,OAAOxB,MACNkY,aAAc,SAAS4E,GACnB,MAAOD,GAAoBC,IAG/B3K,QAAS,WACL2I,EAAe3I,WAGnBiG,WAAY,WACR,MAAOxY,QN3eYiF","file":"dnd.min.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/*globals qq, document, CustomEvent*/\nqq.DragAndDrop = function(o) {\n \"use strict\";\n\n var options,\n HIDE_ZONES_EVENT_NAME = \"qq-hidezones\",\n HIDE_BEFORE_ENTER_ATTR = \"qq-hide-dropzone\",\n uploadDropZones = [],\n droppedFiles = [],\n disposeSupport = new qq.DisposeSupport();\n\n options = {\n dropZoneElements: [],\n allowMultipleItems: true,\n classes: {\n dropActive: null\n },\n callbacks: new qq.DragAndDrop.callbacks()\n };\n\n qq.extend(options, o, true);\n\n function uploadDroppedFiles(files, uploadDropZone) {\n // We need to convert the `FileList` to an actual `Array` to avoid iteration issues\n var filesAsArray = Array.prototype.slice.call(files);\n\n options.callbacks.dropLog(\"Grabbed \" + files.length + \" dropped files.\");\n uploadDropZone.dropDisabled(false);\n options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());\n }\n\n function traverseFileTree(entry) {\n var parseEntryPromise = new qq.Promise();\n\n if (entry.isFile) {\n entry.file(function(file) {\n var name = entry.name,\n fullPath = entry.fullPath,\n indexOfNameInFullPath = fullPath.indexOf(name);\n\n // remove file name from full path string\n fullPath = fullPath.substr(0, indexOfNameInFullPath);\n\n // remove leading slash in full path string\n if (fullPath.charAt(0) === \"/\") {\n fullPath = fullPath.substr(1);\n }\n\n file.qqPath = fullPath;\n droppedFiles.push(file);\n parseEntryPromise.success();\n },\n function(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n });\n }\n else if (entry.isDirectory) {\n getFilesInDirectory(entry).then(\n function allEntriesRead(entries) {\n var entriesLeft = entries.length;\n\n qq.each(entries, function(idx, entry) {\n traverseFileTree(entry).done(function() {\n entriesLeft -= 1;\n\n if (entriesLeft === 0) {\n parseEntryPromise.success();\n }\n });\n });\n\n if (!entries.length) {\n parseEntryPromise.success();\n }\n },\n\n function readFailure(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n }\n );\n }\n\n return parseEntryPromise;\n }\n\n // Promissory. Guaranteed to read all files in the root of the passed directory.\n function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {\n var promise = existingPromise || new qq.Promise(),\n dirReader = reader || entry.createReader();\n\n dirReader.readEntries(\n function readSuccess(entries) {\n var newEntries = accumEntries ? accumEntries.concat(entries) : entries;\n\n if (entries.length) {\n setTimeout(function() { // prevent stack overflow, however unlikely\n getFilesInDirectory(entry, dirReader, newEntries, promise);\n }, 0);\n }\n else {\n promise.success(newEntries);\n }\n },\n\n promise.failure\n );\n\n return promise;\n }\n\n function handleDataTransfer(dataTransfer, uploadDropZone) {\n var pendingFolderPromises = [],\n handleDataTransferPromise = new qq.Promise();\n\n options.callbacks.processingDroppedFiles();\n uploadDropZone.dropDisabled(true);\n\n if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.firefox()) {\n return !e.relatedTarget;\n }\n\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n e.preventDefault();\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n // dt.types.contains check is for firefox\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains(\"Files\")));\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n};\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/edit.gif b/libs/bower/bower_components/fine-uploader/dist/edit.gif
new file mode 100644
index 000000000000..403e7c67dde2
Binary files /dev/null and b/libs/bower/bower_components/fine-uploader/dist/edit.gif differ
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader-gallery.css b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-gallery.css
new file mode 100644
index 000000000000..bdcca3b4ad02
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-gallery.css
@@ -0,0 +1,471 @@
+/* ---------------------------------------
+/* Fine Uploader Gallery View Styles
+/* ---------------------------------------
+
+
+/* Buttons
+------------------------------------------ */
+.qq-gallery .qq-btn
+{
+ float: right;
+ border: none;
+ padding: 0;
+ margin: 0;
+ box-shadow: none;
+}
+
+/* Upload Button
+------------------------------------------ */
+.qq-gallery .qq-upload-button {
+ display: inline;
+ width: 105px;
+ padding: 7px 10px;
+ float: left;
+ text-align: center;
+ background: #00ABC7;
+ color: #FFFFFF;
+ border-radius: 2px;
+ border: 1px solid #37B7CC;
+ box-shadow: 0 1px 1px rgba(255, 255, 255, 0.37) inset,
+ 1px 0 1px rgba(255, 255, 255, 0.07) inset,
+ 0 1px 0 rgba(0, 0, 0, 0.36),
+ 0 -2px 12px rgba(0, 0, 0, 0.08) inset
+}
+.qq-gallery .qq-upload-button-hover {
+ background: #33B6CC;
+}
+.qq-gallery .qq-upload-button-focus {
+ outline: 1px dotted #000000;
+}
+
+
+/* Drop Zone
+------------------------------------------ */
+.qq-gallery.qq-uploader {
+ position: relative;
+ min-height: 200px;
+ max-height: 490px;
+ overflow-y: hidden;
+ width: inherit;
+ border-radius: 6px;
+ border: 1px dashed #CCCCCC;
+ background-color: #FAFAFA;
+ padding: 20px;
+}
+.qq-gallery.qq-uploader:before {
+ content: attr(qq-drop-area-text) " ";
+ position: absolute;
+ font-size: 200%;
+ left: 0;
+ width: 100%;
+ text-align: center;
+ top: 45%;
+ opacity: 0.25;
+ filter: alpha(opacity=25);
+}
+.qq-gallery .qq-upload-drop-area, .qq-upload-extra-drop-area {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ min-height: 30px;
+ z-index: 2;
+ background: #F9F9F9;
+ border-radius: 4px;
+ text-align: center;
+}
+.qq-gallery .qq-upload-drop-area span {
+ display: block;
+ position: absolute;
+ top: 50%;
+ width: 100%;
+ margin-top: -8px;
+ font-size: 16px;
+}
+.qq-gallery .qq-upload-extra-drop-area {
+ position: relative;
+ margin-top: 50px;
+ font-size: 16px;
+ padding-top: 30px;
+ height: 20px;
+ min-height: 40px;
+}
+.qq-gallery .qq-upload-drop-area-active {
+ background: #FDFDFD;
+ border-radius: 4px;
+}
+.qq-gallery .qq-upload-list {
+ margin: 0;
+ padding: 10px 0 0;
+ list-style: none;
+ max-height: 450px;
+ overflow-y: auto;
+ clear: both;
+ box-shadow: none;
+}
+
+
+/* Uploaded Elements
+------------------------------------------ */
+.qq-gallery .qq-upload-list li {
+ display: inline-block;
+ position: relative;
+ max-width: 120px;
+ margin: 0 25px 25px 0;
+ padding: 0;
+ line-height: 16px;
+ font-size: 13px;
+ color: #424242;
+ background-color: #FFFFFF;
+ border-radius: 2px;
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.22);
+ vertical-align: top;
+
+ /* to ensure consistent size of tiles - may need to change if qq-max-size attr on preview img changes */
+ height: 186px;
+}
+
+.qq-gallery .qq-upload-spinner,
+.qq-gallery .qq-upload-size,
+.qq-gallery .qq-upload-retry,
+.qq-gallery .qq-upload-failed-text,
+.qq-gallery .qq-upload-delete,
+.qq-gallery .qq-upload-pause,
+.qq-gallery .qq-upload-continue {
+ display: inline;
+}
+.qq-gallery .qq-upload-retry:hover,
+.qq-gallery .qq-upload-delete:hover,
+.qq-gallery .qq-upload-pause:hover,
+.qq-gallery .qq-upload-continue:hover {
+ background-color: transparent;
+}
+.qq-gallery .qq-upload-delete,
+.qq-gallery .qq-upload-pause,
+.qq-gallery .qq-upload-continue,
+.qq-gallery .qq-upload-cancel {
+ cursor: pointer;
+}
+.qq-gallery .qq-upload-delete,
+.qq-gallery .qq-upload-pause,
+.qq-gallery .qq-upload-continue {
+ border:none;
+ background: none;
+ color: #00A0BA;
+ font-size: 12px;
+ padding: 0;
+}
+/* to ensure consistent size of tiles - only display status text before auto-retry or after failure */
+.qq-gallery .qq-upload-status-text {
+ color: #333333;
+ font-size: 12px;
+ padding-left: 3px;
+ padding-top: 2px;
+ width: inherit;
+ display: none;
+ width: 108px;
+}
+.qq-gallery .qq-upload-fail .qq-upload-status-text {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow-x: hidden;
+ display: block;
+}
+.qq-gallery .qq-upload-retrying .qq-upload-status-text {
+ display: inline-block;
+}
+.qq-gallery .qq-upload-retrying .qq-progress-bar-container {
+ display: none;
+}
+
+.qq-gallery .qq-upload-cancel {
+ background-color: #525252;
+ color: #F7F7F7;
+ font-weight: bold;
+ font-family: Arial, Helvetica, sans-serif;
+ border-radius: 12px;
+ border: none;
+ height: 22px;
+ width: 22px;
+ padding: 4px;
+ position: absolute;
+ right: -5px;
+ top: -6px;
+ margin: 0;
+ line-height: 17px;
+}
+.qq-gallery .qq-upload-cancel:hover {
+ background-color: #525252;
+}
+.qq-gallery .qq-upload-retry {
+ cursor: pointer;
+ position: absolute;
+ top: 30px;
+ left: 50%;
+ margin-left: -31px;
+ box-shadow: 0 1px 1px rgba(255, 255, 255, 0.37) inset,
+ 1px 0 1px rgba(255, 255, 255, 0.07) inset,
+ 0 4px 4px rgba(0, 0, 0, 0.5),
+ 0 -2px 12px rgba(0, 0, 0, 0.08) inset;
+ padding: 3px 4px;
+ border: 1px solid #d2ddc7;
+ border-radius: 2px;
+ color: inherit;
+ background-color: #EBF6E0;
+ z-index: 1;
+}
+.qq-gallery .qq-upload-retry:hover {
+ background-color: #f7ffec;
+}
+
+.qq-gallery .qq-file-info {
+ padding: 10px 6px 4px;
+ margin-top: -3px;
+ border-radius: 0 0 2px 2px;
+ text-align: left;
+ overflow: hidden;
+}
+
+.qq-gallery .qq-file-info .qq-file-name {
+ position: relative;
+}
+
+.qq-gallery .qq-upload-file {
+ display: block;
+ margin-right: 0;
+ margin-bottom: 3px;
+ width: auto;
+
+ /* to ensure consistent size of tiles - constrain text to single line */
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow-x: hidden;
+}
+.qq-gallery .qq-upload-spinner {
+ display: inline-block;
+ background: url("loading.gif");
+ position: absolute;
+ left: 50%;
+ margin-left: -7px;
+ top: 53px;
+ width: 15px;
+ height: 15px;
+ vertical-align: text-bottom;
+}
+.qq-gallery .qq-drop-processing {
+ display: block;
+}
+.qq-gallery .qq-drop-processing-spinner {
+ display: inline-block;
+ background: url("processing.gif");
+ width: 24px;
+ height: 24px;
+ vertical-align: text-bottom;
+}
+.qq-gallery .qq-upload-failed-text {
+ display: none;
+ font-style: italic;
+ font-weight: bold;
+}
+.qq-gallery .qq-upload-failed-icon {
+ display:none;
+ width:15px;
+ height:15px;
+ vertical-align:text-bottom;
+}
+.qq-gallery .qq-upload-fail .qq-upload-failed-text {
+ display: inline;
+}
+.qq-gallery .qq-upload-retrying .qq-upload-failed-text {
+ display: inline;
+}
+.qq-gallery .qq-upload-list li.qq-upload-success {
+ background-color: #F2F7ED;
+}
+.qq-gallery .qq-upload-list li.qq-upload-fail {
+ background-color: #F5EDED;
+ box-shadow: 0 0 1px 0 red;
+ border: 0;
+}
+.qq-gallery .qq-progress-bar {
+ display: block;
+ background: #00abc7;
+ width: 0%;
+ height: 15px;
+ border-radius: 6px;
+ margin-bottom: 3px;
+}
+
+.qq-gallery .qq-total-progress-bar {
+ height: 25px;
+ border-radius: 9px;
+}
+
+.qq-gallery .qq-total-progress-bar-container {
+ margin-left: 9px;
+ display: inline;
+ float: right;
+ width: 500px;
+}
+
+.qq-gallery .qq-upload-size {
+ float: left;
+ font-size: 11px;
+ color: #929292;
+ margin-bottom: 3px;
+ margin-right: 0;
+ display: inline-block;
+}
+
+.qq-gallery INPUT.qq-edit-filename {
+ position: absolute;
+ opacity: 0;
+ filter: alpha(opacity=0);
+ z-index: -1;
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
+}
+
+.qq-gallery .qq-upload-file.qq-editable {
+ cursor: pointer;
+ margin-right: 20px;
+}
+
+.qq-gallery .qq-edit-filename-icon.qq-editable {
+ display: inline-block;
+ cursor: pointer;
+ position: absolute;
+ right: 0;
+ top: 0;
+}
+
+.qq-gallery INPUT.qq-edit-filename.qq-editing {
+ position: static;
+ height: 28px;
+ width: 90px;
+ width: -moz-available;
+ padding: 0 8px;
+ margin-bottom: 3px;
+ border: 1px solid #ccc;
+ border-radius: 2px;
+ font-size: 13px;
+
+ opacity: 1;
+ filter: alpha(opacity=100);
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
+}
+
+.qq-gallery .qq-edit-filename-icon {
+ display: none;
+ background: url("edit.gif");
+ width: 15px;
+ height: 15px;
+ vertical-align: text-bottom;
+}
+.qq-gallery .qq-delete-icon {
+ background: url("trash.gif");
+ width: 15px;
+ height: 15px;
+ vertical-align: sub;
+ display: inline-block;
+}
+.qq-gallery .qq-retry-icon {
+ background: url("retry.gif");
+ width: 15px;
+ height: 15px;
+ vertical-align: sub;
+ display: inline-block;
+ float: none;
+}
+.qq-gallery .qq-continue-icon {
+ background: url("continue.gif");
+ width: 15px;
+ height: 15px;
+ vertical-align: sub;
+ display: inline-block;
+}
+.qq-gallery .qq-pause-icon {
+ background: url("pause.gif");
+ width: 15px;
+ height: 15px;
+ vertical-align: sub;
+ display: inline-block;
+}
+
+.qq-gallery .qq-hide {
+ display: none;
+}
+
+
+/* Thumbnail
+------------------------------------------ */
+.qq-gallery .qq-in-progress .qq-thumbnail-wrapper {
+ /* makes the spinner on top of the thumbnail more visible */
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+}
+.qq-gallery .qq-thumbnail-wrapper {
+ overflow: hidden;
+ position: relative;
+
+ /* to ensure consistent size of tiles - should match qq-max-size attribute value on qq-thumbnail-selector IMG element */
+ height: 120px;
+ width: 120px;
+}
+.qq-gallery .qq-thumbnail-selector {
+ border-radius: 2px 2px 0 0;
+ bottom: 0;
+
+ /* we will override this in the :root thumbnail selector (to help center the preview) for everything other than IE8 */
+ top: 0;
+
+ /* center the thumb horizontally in the tile */
+ margin:auto;
+ display: block;
+}
+
+/* hack to ensure we don't try to center preview in IE8, since -ms-filter doesn't mimic translateY as expected in all cases */
+:root *> .qq-gallery .qq-thumbnail-selector {
+ /* vertically center preview image on tile */
+ position: relative;
+ top: 50%;
+ transform: translateY(-50%);
+ -moz-transform: translateY(-50%);
+ -ms-transform: translateY(-50%);
+ -webkit-transform: translateY(-50%);
+}
+
+/* element styles */
+.qq-gallery.qq-uploader DIALOG {
+ display: none;
+}
+
+.qq-gallery.qq-uploader DIALOG[open] {
+ display: block;
+}
+
+.qq-gallery.qq-uploader DIALOG {
+ display: none;
+}
+
+.qq-gallery.qq-uploader DIALOG[open] {
+ display: block;
+}
+
+.qq-gallery.qq-uploader DIALOG .qq-dialog-buttons {
+ text-align: center;
+ padding-top: 10px;
+}
+
+.qq-gallery.qq-uploader DIALOG .qq-dialog-buttons BUTTON {
+ margin-left: 5px;
+ margin-right: 5px;
+}
+
+.qq-gallery.qq-uploader DIALOG .qq-dialog-message-selector {
+ padding-bottom: 10px;
+}
+
+.qq-gallery .qq-uploader DIALOG::backdrop {
+ background-color: rgba(0, 0, 0, 0.7);
+}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader-gallery.min.css b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-gallery.min.css
new file mode 100644
index 000000000000..4e3a3b075021
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-gallery.min.css
@@ -0,0 +1 @@
+.qq-gallery .qq-btn{float:right;border:none;padding:0;margin:0;box-shadow:none}.qq-gallery .qq-upload-button{display:inline;width:105px;padding:7px 10px;float:left;text-align:center;background:#00ABC7;color:#FFF;border-radius:2px;border:1px solid #37B7CC;box-shadow:0 1px 1px rgba(255,255,255,.37) inset,1px 0 1px rgba(255,255,255,.07) inset,0 1px 0 rgba(0,0,0,.36),0 -2px 12px rgba(0,0,0,.08) inset}.qq-gallery .qq-upload-button-hover{background:#33B6CC}.qq-gallery .qq-upload-button-focus{outline:#000 dotted 1px}.qq-gallery.qq-uploader{position:relative;min-height:200px;max-height:490px;overflow-y:hidden;width:inherit;border-radius:6px;border:1px dashed #CCC;background-color:#FAFAFA;padding:20px}.qq-gallery.qq-uploader:before{content:attr(qq-drop-area-text) " ";position:absolute;font-size:200%;left:0;width:100%;text-align:center;top:45%;opacity:.25;filter:alpha(opacity=25)}.qq-gallery .qq-upload-drop-area,.qq-upload-extra-drop-area{position:absolute;top:0;left:0;width:100%;height:100%;min-height:30px;z-index:2;background:#F9F9F9;border-radius:4px;text-align:center}.qq-gallery .qq-upload-drop-area span{display:block;position:absolute;top:50%;width:100%;margin-top:-8px;font-size:16px}.qq-gallery .qq-upload-extra-drop-area{position:relative;margin-top:50px;font-size:16px;padding-top:30px;height:20px;min-height:40px}.qq-gallery .qq-upload-drop-area-active{background:#FDFDFD;border-radius:4px}.qq-gallery .qq-upload-list{margin:0;padding:10px 0 0;list-style:none;max-height:450px;overflow-y:auto;clear:both;box-shadow:none}.qq-gallery .qq-upload-list li{display:inline-block;position:relative;max-width:120px;margin:0 25px 25px 0;padding:0;line-height:16px;font-size:13px;color:#424242;background-color:#FFF;border-radius:2px;box-shadow:0 1px 1px 0 rgba(0,0,0,.22);vertical-align:top;height:186px}.qq-gallery .qq-upload-continue,.qq-gallery .qq-upload-delete,.qq-gallery .qq-upload-failed-text,.qq-gallery .qq-upload-pause,.qq-gallery .qq-upload-retry,.qq-gallery .qq-upload-size,.qq-gallery .qq-upload-spinner{display:inline}.qq-gallery .qq-upload-continue:hover,.qq-gallery .qq-upload-delete:hover,.qq-gallery .qq-upload-pause:hover,.qq-gallery .qq-upload-retry:hover{background-color:transparent}.qq-gallery .qq-upload-cancel,.qq-gallery .qq-upload-continue,.qq-gallery .qq-upload-delete,.qq-gallery .qq-upload-pause{cursor:pointer}.qq-gallery .qq-upload-continue,.qq-gallery .qq-upload-delete,.qq-gallery .qq-upload-pause{border:none;background:0 0;color:#00A0BA;font-size:12px;padding:0}.qq-gallery .qq-upload-status-text{color:#333;font-size:12px;padding-left:3px;padding-top:2px;display:none;width:108px}.qq-gallery .qq-upload-fail .qq-upload-status-text{text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden;display:block}.qq-gallery .qq-upload-retrying .qq-upload-status-text{display:inline-block}.qq-gallery .qq-upload-retrying .qq-progress-bar-container{display:none}.qq-gallery .qq-upload-cancel{background-color:#525252;color:#F7F7F7;font-weight:700;font-family:Arial,Helvetica,sans-serif;border-radius:12px;border:none;height:22px;width:22px;padding:4px;position:absolute;right:-5px;top:-6px;margin:0;line-height:17px}.qq-gallery .qq-upload-cancel:hover{background-color:#525252}.qq-gallery .qq-upload-retry{cursor:pointer;position:absolute;top:30px;left:50%;margin-left:-31px;box-shadow:0 1px 1px rgba(255,255,255,.37) inset,1px 0 1px rgba(255,255,255,.07) inset,0 4px 4px rgba(0,0,0,.5),0 -2px 12px rgba(0,0,0,.08) inset;padding:3px 4px;border:1px solid #d2ddc7;border-radius:2px;color:inherit;background-color:#EBF6E0;z-index:1}.qq-gallery .qq-upload-retry:hover{background-color:#f7ffec}.qq-gallery .qq-file-info{padding:10px 6px 4px;margin-top:-3px;border-radius:0 0 2px 2px;text-align:left;overflow:hidden}.qq-gallery .qq-file-info .qq-file-name{position:relative}.qq-gallery .qq-upload-file{display:block;margin-right:0;margin-bottom:3px;width:auto;text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden}.qq-gallery .qq-upload-spinner{display:inline-block;background:url(loading.gif);position:absolute;left:50%;margin-left:-7px;top:53px;width:15px;height:15px;vertical-align:text-bottom}.qq-gallery .qq-drop-processing{display:block}.qq-gallery .qq-drop-processing-spinner{display:inline-block;background:url(processing.gif);width:24px;height:24px;vertical-align:text-bottom}.qq-gallery .qq-upload-failed-text{display:none;font-style:italic;font-weight:700}.qq-gallery .qq-upload-failed-icon{display:none;width:15px;height:15px;vertical-align:text-bottom}.qq-gallery .qq-upload-fail .qq-upload-failed-text,.qq-gallery .qq-upload-retrying .qq-upload-failed-text{display:inline}.qq-gallery .qq-upload-list li.qq-upload-success{background-color:#F2F7ED}.qq-gallery .qq-upload-list li.qq-upload-fail{background-color:#F5EDED;box-shadow:0 0 1px 0 red;border:0}.qq-gallery .qq-progress-bar{display:block;background:#00abc7;width:0;height:15px;border-radius:6px;margin-bottom:3px}.qq-gallery .qq-total-progress-bar{height:25px;border-radius:9px}.qq-gallery .qq-total-progress-bar-container{margin-left:9px;display:inline;float:right;width:500px}.qq-gallery .qq-upload-size{float:left;font-size:11px;color:#929292;margin-bottom:3px;margin-right:0;display:inline-block}.qq-gallery INPUT.qq-edit-filename{position:absolute;opacity:0;filter:alpha(opacity=0);z-index:-1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"}.qq-gallery .qq-upload-file.qq-editable{cursor:pointer;margin-right:20px}.qq-gallery .qq-edit-filename-icon.qq-editable{display:inline-block;cursor:pointer;position:absolute;right:0;top:0}.qq-gallery INPUT.qq-edit-filename.qq-editing{position:static;height:28px;width:90px;width:-moz-available;padding:0 8px;margin-bottom:3px;border:1px solid #ccc;border-radius:2px;font-size:13px;opacity:1;filter:alpha(opacity=100);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}.qq-gallery .qq-edit-filename-icon{display:none;background:url(edit.gif);width:15px;height:15px;vertical-align:text-bottom}.qq-gallery .qq-continue-icon,.qq-gallery .qq-delete-icon,.qq-gallery .qq-pause-icon,.qq-gallery .qq-retry-icon{width:15px;height:15px;vertical-align:sub;display:inline-block}.qq-gallery .qq-delete-icon{background:url(trash.gif)}.qq-gallery .qq-retry-icon{background:url(retry.gif);float:none}.qq-gallery .qq-continue-icon{background:url(continue.gif)}.qq-gallery .qq-pause-icon{background:url(pause.gif)}.qq-gallery .qq-hide{display:none}.qq-gallery .qq-in-progress .qq-thumbnail-wrapper{opacity:.5;filter:alpha(opacity=50)}.qq-gallery .qq-thumbnail-wrapper{overflow:hidden;position:relative;height:120px;width:120px}.qq-gallery .qq-thumbnail-selector{border-radius:2px 2px 0 0;bottom:0;top:0;margin:auto;display:block}:root *>.qq-gallery .qq-thumbnail-selector{position:relative;top:50%;transform:translateY(-50%);-moz-transform:translateY(-50%);-ms-transform:translateY(-50%);-webkit-transform:translateY(-50%)}.qq-gallery.qq-uploader DIALOG{display:none}.qq-gallery.qq-uploader DIALOG[open]{display:block}.qq-gallery.qq-uploader DIALOG .qq-dialog-buttons{text-align:center;padding-top:10px}.qq-gallery.qq-uploader DIALOG .qq-dialog-buttons BUTTON{margin-left:5px;margin-right:5px}.qq-gallery.qq-uploader DIALOG .qq-dialog-message-selector{padding-bottom:10px}.qq-gallery .qq-uploader DIALOG::backdrop{background-color:rgba(0,0,0,.7)}/*# sourceMappingURL=fine-uploader-gallery.min.css.map */
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader-gallery.min.css.map b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-gallery.min.css.map
new file mode 100644
index 000000000000..41f0bbeb079e
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-gallery.min.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["_build/fine-uploader-gallery.css"],"names":[],"mappings":"AAOA,oBAEI,MAAO,MACP,YACA,QAAS,EACT,OAAQ,EACR,WAAY,KAKhB,8BACI,QAAS,OACT,MAAO,MACP,QAAS,IAAI,KACb,MAAO,KACP,WAAY,OACZ,WAAY,QACZ,MAAO,KACP,cAAe,IACf,OAAQ,IAAI,MAAM,QAClB,WAAY,EAAE,IAAI,IAAI,sBAA0B,MAAO,IAAI,EAAE,IAAI,sBAA0B,MAAO,EAAE,IAAI,EAAE,gBAAqB,EAAE,KAAK,KAAK,gBAAoB,MAEnK,oCACI,WAAY,QAEhB,oCACI,QAAoB,KAAP,OAAJ,IAMb,wBACI,SAAU,SACV,WAAY,MACZ,WAAY,MACZ,WAAY,OACZ,MAAO,QACP,cAAe,IACf,OAAQ,IAAI,OAAO,KACnB,iBAAkB,QAClB,QAAS,KAEb,+BACI,QAAS,wBAAwB,IACjC,SAAU,SACV,UAAW,KACX,KAAM,EACN,MAAO,KACP,WAAY,OACZ,IAAK,IACL,QAAS,IACT,OAAQ,kBAEZ,iCAAkC,2BAC9B,SAAU,SACV,IAAK,EACL,KAAM,EACN,MAAO,KACP,OAAQ,KACR,WAAY,KACZ,QAAS,EACT,WAAY,QACZ,cAAe,IACf,WAAY,OAEhB,sCACI,QAAS,MACT,SAAU,SACV,IAAK,IACL,MAAO,KACP,WAAY,KACZ,UAAW,KAEf,uCACI,SAAU,SACV,WAAY,KACZ,UAAW,KACX,YAAa,KACb,OAAQ,KACR,WAAY,KAEhB,wCACI,WAAY,QACZ,cAAe,IAEnB,4BACI,OAAQ,EACR,QAAS,KAAK,EAAE,EAChB,WAAY,KACZ,WAAY,MACZ,WAAY,KACZ,MAAO,KACP,WAAY,KAMhB,+BACI,QAAS,aACT,SAAU,SACV,UAAW,MACX,OAAQ,EAAE,KAAK,KAAK,EACpB,QAAS,EACT,YAAa,KACb,UAAW,KACX,MAAO,QACP,iBAAkB,KAClB,cAAe,IACf,WAAY,EAAE,IAAI,IAAI,EAAE,gBACxB,eAAgB,IAGhB,OAA8J,MASlK,gCAFA,8BADA,mCAEA,6BAHA,6BADA,4BADA,+BAOI,QAAS,OAKb,sCAFA,oCACA,mCAFA,mCAII,iBAAkB,YAKtB,8BADA,gCAFA,8BACA,6BAGI,OAAQ,QAIZ,gCAFA,8BACA,6BAEI,YACA,eACA,MAAO,QACP,UAAW,KACX,QAAS,EAGb,mCACI,MAAO,KACP,UAAW,KACX,aAAc,IACd,YAAa,IAEb,QAAS,KACT,MAAO,MAEX,mDACI,cAAe,SACf,YAAa,OACb,WAAY,OACZ,QAAS,MAEb,uDACI,QAAS,aAEb,2DACI,QAAS,KAGb,8BACI,iBAAkB,QAClB,MAAO,QACP,YAAa,IACb,YAAa,MAAO,UAAW,WAC/B,cAAe,KACf,YACA,OAAQ,KACR,MAAO,KACP,QAAS,IACT,SAAU,SACV,MAAO,KACP,IAAK,KACL,OAAQ,EACR,YAAa,KAEjB,oCACI,iBAAkB,QAEtB,6BACI,OAAQ,QACR,SAAU,SACV,IAAK,KACL,KAAM,IACN,YAAa,MACb,WAAY,EAAE,IAAI,IAAI,sBAA0B,MAAO,IAAI,EAAE,IAAI,sBAA0B,MAAO,EAAE,IAAI,IAAI,eAAoB,EAAE,KAAK,KAAK,gBAAoB,MAChK,QAAS,IAAI,IACb,OAAQ,IAAI,MAAM,QAClB,cAAe,IACf,MAAO,QACP,iBAAkB,QAClB,QAAS,EAEb,mCACI,iBAAkB,QAGtB,0BACI,QAAS,KAAK,IAAI,IAClB,WAAY,KACZ,cAAe,EAAE,EAAE,IAAI,IACvB,WAAY,KACZ,SAAU,OAGd,wCACI,SAAU,SAGd,4BACI,QAAS,MACT,aAAc,EACd,cAAe,IACf,MAAO,KAGP,cAAqV,SACrV,YAAa,OACb,WAAY,OAEhB,+BACI,QAAS,aACT,WAAY,iBACZ,SAAU,SACV,KAAM,IACN,YAAa,KACb,IAAK,KACL,MAAO,KACP,OAAQ,KACR,eAAgB,YAEpB,gCACI,QAAS,MAEb,wCACI,QAAS,aACT,WAAY,oBACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAEpB,mCACI,QAAS,KACT,WAAY,OACZ,YAAa,IAEjB,mCACI,QAAQ,KACR,MAAM,KACN,OAAO,KACP,eAAe,YAEnB,mDAGA,uDAFI,QAAS,OAKb,iDACI,iBAAkB,QAEtB,8CACI,iBAAkB,QAClB,WAAY,EAAE,EAAE,IAAI,EAAE,IACtB,OAAQ,EAEZ,6BACI,QAAS,MACT,WAAY,QACZ,MAAO,EACP,OAAQ,KACR,cAAe,IACf,cAAe,IAGnB,mCACI,OAAQ,KACR,cAAe,IAGnB,6CACI,YAAa,IACb,QAAS,OACT,MAAO,MACP,MAAO,MAGX,4BACI,MAAO,KACP,UAAW,KACX,MAAO,QACP,cAAe,IACf,aAAc,EACd,QAAS,aAGb,mCACI,SAAU,SACV,QAAS,EACT,OAAQ,iBACR,QAAS,GACT,WAAY,qDAGhB,wCACI,OAAQ,QACR,aAAc,KAGlB,+CACI,QAAS,aACT,OAAQ,QACR,SAAU,SACV,MAAO,EACP,IAAK,EAGT,8CACI,SAAU,OACV,OAAQ,KACR,MAAO,KACP,MAAO,eACP,QAAS,EAAE,IACX,cAAe,IACf,OAAQ,IAAI,MAAM,KAClB,cAAe,IACf,UAAW,KAEX,QAAS,EACT,OAAQ,mBACR,WAAY,uDAGhB,mCACI,QAAS,KACT,WAAY,cACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAiBpB,8BAfA,4BAsBA,2BAfA,2BAiBI,MAAO,KACP,OAAQ,KACR,eAAgB,IAChB,QAAS,aA3Bb,4BACI,WAAY,eAMhB,2BACI,WAAY,eAKZ,MAAO,KAEX,8BACI,WAAY,kBAMhB,2BACI,WAAY,eAOhB,qBACI,QAAS,KAMb,kDAEI,QAAmH,GACnH,OAAQ,kBAEZ,kCACI,SAAU,OACV,SAAU,SAGV,OAA2O,MAC3O,MAAO,MAEX,mCACI,cAAe,IAAI,IAAI,EAAE,EACzB,OAAQ,EAGR,IAA+V,EAG/V,OAAiZ,KACjZ,QAAS,MAIb,2CAEI,SAAikB,SACjkB,IAAK,IACL,UAAW,iBACX,eAAgB,iBAChB,cAAe,iBACf,kBAAmB,iBAYvB,+BACI,QAAS,KAGb,qCACI,QAAS,MAGb,kDACI,WAAY,OACZ,YAAa,KAGjB,yDACI,YAAa,IACb,aAAc,IAGlB,2DACI,eAAgB,KAGpB,0CACI,iBAAkB"}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader-new.css b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-new.css
new file mode 100644
index 000000000000..c7678a3b0efa
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-new.css
@@ -0,0 +1,354 @@
+/* ---------------------------------------
+/* Fine Uploader Styles
+/* ---------------------------------------
+
+/* Buttons
+------------------------------------------ */
+.qq-btn
+{
+ box-shadow: 0 1px 1px rgba(255, 255, 255, 0.37) inset,
+ 1px 0 1px rgba(255, 255, 255, 0.07) inset,
+ 0 1px 0 rgba(0, 0, 0, 0.36),
+ 0 -2px 12px rgba(0, 0, 0, 0.08) inset;
+ padding: 3px 4px;
+ border: 1px solid #CCCCCC;
+ border-radius: 2px;
+ color: inherit;
+ background-color: #FFFFFF;
+}
+.qq-upload-delete, .qq-upload-pause, .qq-upload-continue {
+ display: inline;
+}
+.qq-upload-delete
+{
+ background-color: #e65c47;
+ color: #FAFAFA;
+ border-color: #dc523d;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.55);
+}
+.qq-upload-delete:hover {
+ background-color: #f56b56;
+ }
+.qq-upload-cancel
+{
+ background-color: #F5D7D7;
+ border-color: #e6c8c8;
+}
+.qq-upload-cancel:hover {
+ background-color: #ffe1e1;
+}
+.qq-upload-retry
+{
+ background-color: #EBF6E0;
+ border-color: #d2ddc7;
+}
+.qq-upload-retry:hover {
+ background-color: #f7ffec;
+}
+.qq-upload-pause, .qq-upload-continue {
+ background-color: #00ABC7;
+ color: #FAFAFA;
+ border-color: #2dadc2;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.55);
+}
+.qq-upload-pause:hover, .qq-upload-continue:hover {
+ background-color: #0fbad6;
+}
+
+/* Upload Button
+------------------------------------------ */
+.qq-upload-button {
+ display: inline;
+ width: 105px;
+ margin-bottom: 10px;
+ padding: 7px 10px;
+ text-align: center;
+ float: left;
+ background: #00ABC7;
+ color: #FFFFFF;
+ border-radius: 2px;
+ border: 1px solid #2dadc2;
+ box-shadow: 0 1px 1px rgba(255, 255, 255, 0.37) inset,
+ 1px 0 1px rgba(255, 255, 255, 0.07) inset,
+ 0 1px 0 rgba(0, 0, 0, 0.36),
+ 0 -2px 12px rgba(0, 0, 0, 0.08) inset;
+}
+.qq-upload-button-hover {
+ background: #33B6CC;
+}
+.qq-upload-button-focus {
+ outline: 1px dotted #000000;
+}
+
+
+/* Drop Zone
+------------------------------------------ */
+.qq-uploader {
+ position: relative;
+ min-height: 200px;
+ max-height: 490px;
+ overflow-y: hidden;
+ width: inherit;
+ border-radius: 6px;
+ background-color: #FDFDFD;
+ border: 1px dashed #CCCCCC;
+ padding: 20px;
+}
+.qq-uploader:before {
+ content: attr(qq-drop-area-text) " ";
+ position: absolute;
+ font-size: 200%;
+ left: 0;
+ width: 100%;
+ text-align: center;
+ top: 45%;
+ opacity: 0.25;
+}
+.qq-upload-drop-area, .qq-upload-extra-drop-area {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ min-height: 30px;
+ z-index: 2;
+ background: #F9F9F9;
+ border-radius: 4px;
+ border: 1px dashed #CCCCCC;
+ text-align: center;
+}
+.qq-upload-drop-area span {
+ display: block;
+ position: absolute;
+ top: 50%;
+ width: 100%;
+ margin-top: -8px;
+ font-size: 16px;
+}
+.qq-upload-extra-drop-area {
+ position: relative;
+ margin-top: 50px;
+ font-size: 16px;
+ padding-top: 30px;
+ height: 20px;
+ min-height: 40px;
+}
+.qq-upload-drop-area-active {
+ background: #FDFDFD;
+ border-radius: 4px;
+ border: 1px dashed #CCCCCC;
+}
+.qq-upload-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ max-height: 450px;
+ overflow-y: auto;
+ box-shadow: 0px 1px 0px rgba(15, 15, 50, 0.14);
+ clear: both;
+}
+
+
+/* Uploaded Elements
+------------------------------------------ */
+.qq-upload-list li {
+ margin: 0;
+ padding: 9px;
+ line-height: 15px;
+ font-size: 16px;
+ color: #424242;
+ background-color: #F6F6F6;
+ border-top: 1px solid #FFFFFF;
+ border-bottom: 1px solid #DDDDDD;
+}
+.qq-upload-list li:first-child {
+ border-top: none;
+}
+.qq-upload-list li:last-child {
+ border-bottom: none;
+}
+
+.qq-upload-file, .qq-upload-spinner, .qq-upload-size,
+.qq-upload-cancel, .qq-upload-retry, .qq-upload-failed-text,
+.qq-upload-delete, .qq-upload-pause, .qq-upload-continue {
+ margin-right: 12px;
+ display: inline;
+}
+.qq-upload-file {
+ vertical-align: middle;
+ display: inline-block;
+ width: 300px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow-x: hidden;
+ height: 18px;
+}
+.qq-upload-spinner {
+ display: inline-block;
+ background: url("loading.gif");
+ width: 15px;
+ height: 15px;
+ vertical-align: text-bottom;
+}
+.qq-drop-processing {
+ display: block;
+}
+.qq-drop-processing-spinner {
+ display: inline-block;
+ background: url("processing.gif");
+ width: 24px;
+ height: 24px;
+ vertical-align: text-bottom;
+}
+.qq-upload-size, .qq-upload-cancel, .qq-upload-retry,
+.qq-upload-delete, .qq-upload-pause, .qq-upload-continue {
+ font-size: 12px;
+ font-weight: normal;
+ cursor: pointer;
+ vertical-align: middle;
+}
+.qq-upload-status-text {
+ font-size: 14px;
+ font-weight: bold;
+ display: block;
+}
+.qq-upload-failed-text {
+ display: none;
+ font-style: italic;
+ font-weight: bold;
+}
+.qq-upload-failed-icon {
+ display:none;
+ width:15px;
+ height:15px;
+ vertical-align:text-bottom;
+}
+.qq-upload-fail .qq-upload-failed-text {
+ display: inline;
+}
+.qq-upload-retrying .qq-upload-failed-text {
+ display: inline;
+}
+.qq-upload-list li.qq-upload-success {
+ background-color: #EBF6E0;
+ color: #424242;
+ border-bottom: 1px solid #D3DED1;
+ border-top: 1px solid #F7FFF5;
+}
+.qq-upload-list li.qq-upload-fail {
+ background-color: #F5D7D7;
+ color: #424242;
+ border-bottom: 1px solid #DECACA;
+ border-top: 1px solid #FCE6E6;
+}
+.qq-progress-bar {
+ display: block;
+ display: block;
+ background: #00abc7;
+ width: 0%;
+ height: 15px;
+ border-radius: 6px;
+ margin-bottom: 3px;
+}
+
+.qq-total-progress-bar {
+ height: 25px;
+ border-radius: 9px;
+}
+
+.qq-total-progress-bar-container {
+ margin-left: 9px;
+ display: inline;
+ float: right;
+ width: 500px;
+}
+
+INPUT.qq-edit-filename {
+ position: absolute;
+ opacity: 0;
+ filter: alpha(opacity=0);
+ z-index: -1;
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
+}
+
+.qq-upload-file.qq-editable {
+ cursor: pointer;
+ margin-right: 4px;
+}
+
+.qq-edit-filename-icon.qq-editable {
+ display: inline-block;
+ cursor: pointer;
+}
+
+INPUT.qq-edit-filename.qq-editing {
+ position: static;
+ height: 28px;
+ padding: 0 8px;
+ margin-right: 10px;
+ margin-bottom: -5px;
+ border: 1px solid #ccc;
+ border-radius: 2px;
+ font-size: 16px;
+
+ opacity: 1;
+ filter: alpha(opacity=100);
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
+}
+
+.qq-edit-filename-icon {
+ display: none;
+ background: url("edit.gif");
+ width: 15px;
+ height: 15px;
+ vertical-align: text-bottom;
+ margin-right: 16px;
+}
+
+.qq-hide {
+ display: none;
+}
+
+
+/* Thumbnail
+------------------------------------------ */
+.qq-thumbnail-selector {
+ vertical-align: middle;
+ margin-right: 12px;
+}
+
+
+/* element styles */
+.qq-uploader DIALOG {
+ display: none;
+}
+
+.qq-uploader DIALOG[open] {
+ display: block;
+}
+
+.qq-uploader DIALOG {
+ display: none;
+}
+
+.qq-uploader DIALOG[open] {
+ display: block;
+}
+
+.qq-uploader DIALOG .qq-dialog-buttons {
+ text-align: center;
+ padding-top: 10px;
+}
+
+.qq-uploader DIALOG .qq-dialog-buttons BUTTON {
+ margin-left: 5px;
+ margin-right: 5px;
+}
+
+.qq-uploader DIALOG .qq-dialog-message-selector {
+ padding-bottom: 10px;
+}
+
+.qq-uploader DIALOG::backdrop {
+ background-color: rgba(0, 0, 0, 0.7);
+}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader-new.min.css b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-new.min.css
new file mode 100644
index 000000000000..58422f2f6048
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-new.min.css
@@ -0,0 +1 @@
+.qq-btn,.qq-upload-button{box-shadow:0 1px 1px rgba(255,255,255,.37) inset,1px 0 1px rgba(255,255,255,.07) inset,0 1px 0 rgba(0,0,0,.36),0 -2px 12px rgba(0,0,0,.08) inset}.qq-btn{padding:3px 4px;border:1px solid #CCC;border-radius:2px;color:inherit;background-color:#FFF}.qq-upload-delete{background-color:#e65c47;color:#FAFAFA;border-color:#dc523d;text-shadow:0 1px 1px rgba(0,0,0,.55)}.qq-upload-delete:hover{background-color:#f56b56}.qq-upload-cancel{background-color:#F5D7D7;border-color:#e6c8c8}.qq-upload-cancel:hover{background-color:#ffe1e1}.qq-upload-retry{background-color:#EBF6E0;border-color:#d2ddc7}.qq-upload-retry:hover{background-color:#f7ffec}.qq-upload-continue,.qq-upload-pause{background-color:#00ABC7;color:#FAFAFA;border-color:#2dadc2;text-shadow:0 1px 1px rgba(0,0,0,.55)}.qq-upload-continue:hover,.qq-upload-pause:hover{background-color:#0fbad6}.qq-upload-button{display:inline;width:105px;margin-bottom:10px;padding:7px 10px;text-align:center;float:left;background:#00ABC7;color:#FFF;border-radius:2px;border:1px solid #2dadc2}.qq-upload-button-hover{background:#33B6CC}.qq-upload-button-focus{outline:#000 dotted 1px}.qq-uploader{position:relative;min-height:200px;max-height:490px;overflow-y:hidden;width:inherit;border-radius:6px;background-color:#FDFDFD;border:1px dashed #CCC;padding:20px}.qq-uploader:before{content:attr(qq-drop-area-text) " ";position:absolute;font-size:200%;left:0;width:100%;text-align:center;top:45%;opacity:.25}.qq-upload-drop-area,.qq-upload-extra-drop-area{position:absolute;top:0;left:0;width:100%;height:100%;min-height:30px;z-index:2;background:#F9F9F9;border-radius:4px;border:1px dashed #CCC;text-align:center}.qq-upload-drop-area span{display:block;position:absolute;top:50%;width:100%;margin-top:-8px;font-size:16px}.qq-upload-extra-drop-area{position:relative;margin-top:50px;font-size:16px;padding-top:30px;height:20px;min-height:40px}.qq-upload-drop-area-active{background:#FDFDFD;border-radius:4px;border:1px dashed #CCC}.qq-upload-list{margin:0;padding:0;list-style:none;max-height:450px;overflow-y:auto;box-shadow:0 1px 0 rgba(15,15,50,.14);clear:both}.qq-upload-list li{margin:0;padding:9px;line-height:15px;font-size:16px;color:#424242;background-color:#F6F6F6;border-top:1px solid #FFF;border-bottom:1px solid #DDD}.qq-upload-list li:first-child{border-top:none}.qq-upload-list li:last-child{border-bottom:none}.qq-upload-cancel,.qq-upload-continue,.qq-upload-delete,.qq-upload-failed-text,.qq-upload-file,.qq-upload-pause,.qq-upload-retry,.qq-upload-size,.qq-upload-spinner{margin-right:12px;display:inline}.qq-upload-file{vertical-align:middle;display:inline-block;width:300px;text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden;height:18px}.qq-upload-spinner{display:inline-block;background:url(loading.gif);width:15px;height:15px;vertical-align:text-bottom}.qq-drop-processing{display:block}.qq-drop-processing-spinner{display:inline-block;background:url(processing.gif);width:24px;height:24px;vertical-align:text-bottom}.qq-upload-cancel,.qq-upload-continue,.qq-upload-delete,.qq-upload-pause,.qq-upload-retry,.qq-upload-size{font-size:12px;font-weight:400;cursor:pointer;vertical-align:middle}.qq-upload-status-text{font-size:14px;font-weight:700;display:block}.qq-upload-failed-text{display:none;font-style:italic;font-weight:700}.qq-upload-failed-icon{display:none;width:15px;height:15px;vertical-align:text-bottom}.qq-upload-fail .qq-upload-failed-text,.qq-upload-retrying .qq-upload-failed-text{display:inline}.qq-upload-list li.qq-upload-success{background-color:#EBF6E0;color:#424242;border-bottom:1px solid #D3DED1;border-top:1px solid #F7FFF5}.qq-upload-list li.qq-upload-fail{background-color:#F5D7D7;color:#424242;border-bottom:1px solid #DECACA;border-top:1px solid #FCE6E6}.qq-progress-bar{display:block;background:#00abc7;width:0;height:15px;border-radius:6px;margin-bottom:3px}.qq-total-progress-bar{height:25px;border-radius:9px}.qq-total-progress-bar-container{margin-left:9px;display:inline;float:right;width:500px}INPUT.qq-edit-filename{position:absolute;opacity:0;filter:alpha(opacity=0);z-index:-1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"}.qq-upload-file.qq-editable{cursor:pointer;margin-right:4px}.qq-edit-filename-icon.qq-editable{display:inline-block;cursor:pointer}.qq-hide,.qq-uploader DIALOG{display:none}INPUT.qq-edit-filename.qq-editing{position:static;height:28px;padding:0 8px;margin-right:10px;margin-bottom:-5px;border:1px solid #ccc;border-radius:2px;font-size:16px;opacity:1;filter:alpha(opacity=100);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}.qq-edit-filename-icon{display:none;background:url(edit.gif);width:15px;height:15px;vertical-align:text-bottom;margin-right:16px}.qq-thumbnail-selector{vertical-align:middle;margin-right:12px}.qq-uploader DIALOG[open]{display:block}.qq-uploader DIALOG .qq-dialog-buttons{text-align:center;padding-top:10px}.qq-uploader DIALOG .qq-dialog-buttons BUTTON{margin-left:5px;margin-right:5px}.qq-uploader DIALOG .qq-dialog-message-selector{padding-bottom:10px}.qq-uploader DIALOG::backdrop{background-color:rgba(0,0,0,.7)}/*# sourceMappingURL=fine-uploader-new.min.css.map */
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader-new.min.css.map b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-new.min.css.map
new file mode 100644
index 000000000000..2dab29aa6b36
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader-new.min.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["_build/fine-uploader-new.css"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader.core.js b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.core.js
new file mode 100644
index 000000000000..d7706a7ff099
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.core.js
@@ -0,0 +1,5515 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+(function(global) {
+ var qq = function(element) {
+ "use strict";
+ return {
+ hide: function() {
+ element.style.display = "none";
+ return this;
+ },
+ attach: function(type, fn) {
+ if (element.addEventListener) {
+ element.addEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.attachEvent("on" + type, fn);
+ }
+ return function() {
+ qq(element).detach(type, fn);
+ };
+ },
+ detach: function(type, fn) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.detachEvent("on" + type, fn);
+ }
+ return this;
+ },
+ contains: function(descendant) {
+ if (!descendant) {
+ return false;
+ }
+ if (element === descendant) {
+ return true;
+ }
+ if (element.contains) {
+ return element.contains(descendant);
+ } else {
+ return !!(descendant.compareDocumentPosition(element) & 8);
+ }
+ },
+ insertBefore: function(elementB) {
+ elementB.parentNode.insertBefore(element, elementB);
+ return this;
+ },
+ remove: function() {
+ element.parentNode.removeChild(element);
+ return this;
+ },
+ css: function(styles) {
+ if (element.style == null) {
+ throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");
+ }
+ if (styles.opacity != null) {
+ if (typeof element.style.opacity !== "string" && typeof element.filters !== "undefined") {
+ styles.filter = "alpha(opacity=" + Math.round(100 * styles.opacity) + ")";
+ }
+ }
+ qq.extend(element.style, styles);
+ return this;
+ },
+ hasClass: function(name, considerParent) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));
+ },
+ addClass: function(name) {
+ if (!qq(element).hasClass(name)) {
+ element.className += " " + name;
+ }
+ return this;
+ },
+ removeClass: function(name) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ element.className = element.className.replace(re, " ").replace(/^\s+|\s+$/g, "");
+ return this;
+ },
+ getByClass: function(className, first) {
+ var candidates, result = [];
+ if (first && element.querySelector) {
+ return element.querySelector("." + className);
+ } else if (element.querySelectorAll) {
+ return element.querySelectorAll("." + className);
+ }
+ candidates = element.getElementsByTagName("*");
+ qq.each(candidates, function(idx, val) {
+ if (qq(val).hasClass(className)) {
+ result.push(val);
+ }
+ });
+ return first ? result[0] : result;
+ },
+ getFirstByClass: function(className) {
+ return qq(element).getByClass(className, true);
+ },
+ children: function() {
+ var children = [], child = element.firstChild;
+ while (child) {
+ if (child.nodeType === 1) {
+ children.push(child);
+ }
+ child = child.nextSibling;
+ }
+ return children;
+ },
+ setText: function(text) {
+ element.innerText = text;
+ element.textContent = text;
+ return this;
+ },
+ clearText: function() {
+ return qq(element).setText("");
+ },
+ hasAttribute: function(attrName) {
+ var attrVal;
+ if (element.hasAttribute) {
+ if (!element.hasAttribute(attrName)) {
+ return false;
+ }
+ return /^false$/i.exec(element.getAttribute(attrName)) == null;
+ } else {
+ attrVal = element[attrName];
+ if (attrVal === undefined) {
+ return false;
+ }
+ return /^false$/i.exec(attrVal) == null;
+ }
+ }
+ };
+ };
+ (function() {
+ "use strict";
+ qq.canvasToBlob = function(canvas, mime, quality) {
+ return qq.dataUriToBlob(canvas.toDataURL(mime, quality));
+ };
+ qq.dataUriToBlob = function(dataUri) {
+ var arrayBuffer, byteString, createBlob = function(data, mime) {
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }, intArray, mimeString;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return createBlob(arrayBuffer, mimeString);
+ };
+ qq.log = function(message, level) {
+ if (window.console) {
+ if (!level || level === "info") {
+ window.console.log(message);
+ } else {
+ if (window.console[level]) {
+ window.console[level](message);
+ } else {
+ window.console.log("<" + level + "> " + message);
+ }
+ }
+ }
+ };
+ qq.isObject = function(variable) {
+ return variable && !variable.nodeType && Object.prototype.toString.call(variable) === "[object Object]";
+ };
+ qq.isFunction = function(variable) {
+ return typeof variable === "function";
+ };
+ qq.isArray = function(value) {
+ return Object.prototype.toString.call(value) === "[object Array]" || value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer;
+ };
+ qq.isItemList = function(maybeItemList) {
+ return Object.prototype.toString.call(maybeItemList) === "[object DataTransferItemList]";
+ };
+ qq.isNodeList = function(maybeNodeList) {
+ return Object.prototype.toString.call(maybeNodeList) === "[object NodeList]" || maybeNodeList.item && maybeNodeList.namedItem;
+ };
+ qq.isString = function(maybeString) {
+ return Object.prototype.toString.call(maybeString) === "[object String]";
+ };
+ qq.trimStr = function(string) {
+ if (String.prototype.trim) {
+ return string.trim();
+ }
+ return string.replace(/^\s+|\s+$/g, "");
+ };
+ qq.format = function(str) {
+ var args = Array.prototype.slice.call(arguments, 1), newStr = str, nextIdxToReplace = newStr.indexOf("{}");
+ qq.each(args, function(idx, val) {
+ var strBefore = newStr.substring(0, nextIdxToReplace), strAfter = newStr.substring(nextIdxToReplace + 2);
+ newStr = strBefore + val + strAfter;
+ nextIdxToReplace = newStr.indexOf("{}", nextIdxToReplace + val.length);
+ if (nextIdxToReplace < 0) {
+ return false;
+ }
+ });
+ return newStr;
+ };
+ qq.isFile = function(maybeFile) {
+ return window.File && Object.prototype.toString.call(maybeFile) === "[object File]";
+ };
+ qq.isFileList = function(maybeFileList) {
+ return window.FileList && Object.prototype.toString.call(maybeFileList) === "[object FileList]";
+ };
+ qq.isFileOrInput = function(maybeFileOrInput) {
+ return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);
+ };
+ qq.isInput = function(maybeInput, notFile) {
+ var evaluateType = function(type) {
+ var normalizedType = type.toLowerCase();
+ if (notFile) {
+ return normalizedType !== "file";
+ }
+ return normalizedType === "file";
+ };
+ if (window.HTMLInputElement) {
+ if (Object.prototype.toString.call(maybeInput) === "[object HTMLInputElement]") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ if (maybeInput.tagName) {
+ if (maybeInput.tagName.toLowerCase() === "input") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ qq.isBlob = function(maybeBlob) {
+ if (window.Blob && Object.prototype.toString.call(maybeBlob) === "[object Blob]") {
+ return true;
+ }
+ };
+ qq.isXhrUploadSupported = function() {
+ var input = document.createElement("input");
+ input.type = "file";
+ return input.multiple !== undefined && typeof File !== "undefined" && typeof FormData !== "undefined" && typeof qq.createXhrInstance().upload !== "undefined";
+ };
+ qq.createXhrInstance = function() {
+ if (window.XMLHttpRequest) {
+ return new XMLHttpRequest();
+ }
+ try {
+ return new ActiveXObject("MSXML2.XMLHTTP.3.0");
+ } catch (error) {
+ qq.log("Neither XHR or ActiveX are supported!", "error");
+ return null;
+ }
+ };
+ qq.isFolderDropSupported = function(dataTransfer) {
+ return dataTransfer.items && dataTransfer.items.length > 0 && dataTransfer.items[0].webkitGetAsEntry;
+ };
+ qq.isFileChunkingSupported = function() {
+ return !qq.androidStock() && qq.isXhrUploadSupported() && (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);
+ };
+ qq.sliceBlob = function(fileOrBlob, start, end) {
+ var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;
+ return slicer.call(fileOrBlob, start, end);
+ };
+ qq.arrayBufferToHex = function(buffer) {
+ var bytesAsHex = "", bytes = new Uint8Array(buffer);
+ qq.each(bytes, function(idx, byt) {
+ var byteAsHexStr = byt.toString(16);
+ if (byteAsHexStr.length < 2) {
+ byteAsHexStr = "0" + byteAsHexStr;
+ }
+ bytesAsHex += byteAsHexStr;
+ });
+ return bytesAsHex;
+ };
+ qq.readBlobToHex = function(blob, startOffset, length) {
+ var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), fileReader = new FileReader(), promise = new qq.Promise();
+ fileReader.onload = function() {
+ promise.success(qq.arrayBufferToHex(fileReader.result));
+ };
+ fileReader.onerror = promise.failure;
+ fileReader.readAsArrayBuffer(initialBlob);
+ return promise;
+ };
+ qq.extend = function(first, second, extendNested) {
+ qq.each(second, function(prop, val) {
+ if (extendNested && qq.isObject(val)) {
+ if (first[prop] === undefined) {
+ first[prop] = {};
+ }
+ qq.extend(first[prop], val, true);
+ } else {
+ first[prop] = val;
+ }
+ });
+ return first;
+ };
+ qq.override = function(target, sourceFn) {
+ var super_ = {}, source = sourceFn(super_);
+ qq.each(source, function(srcPropName, srcPropVal) {
+ if (target[srcPropName] !== undefined) {
+ super_[srcPropName] = target[srcPropName];
+ }
+ target[srcPropName] = srcPropVal;
+ });
+ return target;
+ };
+ qq.indexOf = function(arr, elt, from) {
+ if (arr.indexOf) {
+ return arr.indexOf(elt, from);
+ }
+ from = from || 0;
+ var len = arr.length;
+ if (from < 0) {
+ from += len;
+ }
+ for (;from < len; from += 1) {
+ if (arr.hasOwnProperty(from) && arr[from] === elt) {
+ return from;
+ }
+ }
+ return -1;
+ };
+ qq.getUniqueId = function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
+ return v.toString(16);
+ });
+ };
+ qq.ie = function() {
+ return navigator.userAgent.indexOf("MSIE") !== -1 || navigator.userAgent.indexOf("Trident") !== -1;
+ };
+ qq.ie7 = function() {
+ return navigator.userAgent.indexOf("MSIE 7") !== -1;
+ };
+ qq.ie8 = function() {
+ return navigator.userAgent.indexOf("MSIE 8") !== -1;
+ };
+ qq.ie10 = function() {
+ return navigator.userAgent.indexOf("MSIE 10") !== -1;
+ };
+ qq.ie11 = function() {
+ return qq.ie() && navigator.userAgent.indexOf("rv:11") !== -1;
+ };
+ qq.edge = function() {
+ return navigator.userAgent.indexOf("Edge") >= 0;
+ };
+ qq.safari = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Apple") !== -1;
+ };
+ qq.chrome = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Google") !== -1;
+ };
+ qq.opera = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Opera") !== -1;
+ };
+ qq.firefox = function() {
+ return !qq.edge() && !qq.ie11() && navigator.userAgent.indexOf("Mozilla") !== -1 && navigator.vendor !== undefined && navigator.vendor === "";
+ };
+ qq.windows = function() {
+ return navigator.platform === "Win32";
+ };
+ qq.android = function() {
+ return navigator.userAgent.toLowerCase().indexOf("android") !== -1;
+ };
+ qq.androidStock = function() {
+ return qq.android() && navigator.userAgent.toLowerCase().indexOf("chrome") < 0;
+ };
+ qq.ios6 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 6_") !== -1;
+ };
+ qq.ios7 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 7_") !== -1;
+ };
+ qq.ios8 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_") !== -1;
+ };
+ qq.ios800 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_0 ") !== -1;
+ };
+ qq.ios = function() {
+ return navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("iPod") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1;
+ };
+ qq.iosChrome = function() {
+ return qq.ios() && navigator.userAgent.indexOf("CriOS") !== -1;
+ };
+ qq.iosSafari = function() {
+ return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf("Safari") !== -1;
+ };
+ qq.iosSafariWebView = function() {
+ return qq.ios() && !qq.iosChrome() && !qq.iosSafari();
+ };
+ qq.preventDefault = function(e) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ };
+ qq.toElement = function() {
+ var div = document.createElement("div");
+ return function(html) {
+ div.innerHTML = html;
+ var element = div.firstChild;
+ div.removeChild(element);
+ return element;
+ };
+ }();
+ qq.each = function(iterableItem, callback) {
+ var keyOrIndex, retVal;
+ if (iterableItem) {
+ if (window.Storage && iterableItem.constructor === window.Storage) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isString(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else {
+ for (keyOrIndex in iterableItem) {
+ if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ };
+ qq.bind = function(oldFunc, context) {
+ if (qq.isFunction(oldFunc)) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ return function() {
+ var newArgs = qq.extend([], args);
+ if (arguments.length) {
+ newArgs = newArgs.concat(Array.prototype.slice.call(arguments));
+ }
+ return oldFunc.apply(context, newArgs);
+ };
+ }
+ throw new Error("first parameter must be a function!");
+ };
+ qq.obj2url = function(obj, temp, prefixDone) {
+ var uristrings = [], prefix = "&", add = function(nextObj, i) {
+ var nextTemp = temp ? /\[\]$/.test(temp) ? temp : temp + "[" + i + "]" : i;
+ if (nextTemp !== "undefined" && i !== "undefined") {
+ uristrings.push(typeof nextObj === "object" ? qq.obj2url(nextObj, nextTemp, true) : Object.prototype.toString.call(nextObj) === "[object Function]" ? encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj));
+ }
+ };
+ if (!prefixDone && temp) {
+ prefix = /\?/.test(temp) ? /\?$/.test(temp) ? "" : "&" : "?";
+ uristrings.push(temp);
+ uristrings.push(qq.obj2url(obj));
+ } else if (Object.prototype.toString.call(obj) === "[object Array]" && typeof obj !== "undefined") {
+ qq.each(obj, function(idx, val) {
+ add(val, idx);
+ });
+ } else if (typeof obj !== "undefined" && obj !== null && typeof obj === "object") {
+ qq.each(obj, function(prop, val) {
+ add(val, prop);
+ });
+ } else {
+ uristrings.push(encodeURIComponent(temp) + "=" + encodeURIComponent(obj));
+ }
+ if (temp) {
+ return uristrings.join(prefix);
+ } else {
+ return uristrings.join(prefix).replace(/^&/, "").replace(/%20/g, "+");
+ }
+ };
+ qq.obj2FormData = function(obj, formData, arrayKeyName) {
+ if (!formData) {
+ formData = new FormData();
+ }
+ qq.each(obj, function(key, val) {
+ key = arrayKeyName ? arrayKeyName + "[" + key + "]" : key;
+ if (qq.isObject(val)) {
+ qq.obj2FormData(val, formData, key);
+ } else if (qq.isFunction(val)) {
+ formData.append(key, val());
+ } else {
+ formData.append(key, val);
+ }
+ });
+ return formData;
+ };
+ qq.obj2Inputs = function(obj, form) {
+ var input;
+ if (!form) {
+ form = document.createElement("form");
+ }
+ qq.obj2FormData(obj, {
+ append: function(key, val) {
+ input = document.createElement("input");
+ input.setAttribute("name", key);
+ input.setAttribute("value", val);
+ form.appendChild(input);
+ }
+ });
+ return form;
+ };
+ qq.parseJson = function(json) {
+ if (window.JSON && qq.isFunction(JSON.parse)) {
+ return JSON.parse(json);
+ } else {
+ return eval("(" + json + ")");
+ }
+ };
+ qq.getExtension = function(filename) {
+ var extIdx = filename.lastIndexOf(".") + 1;
+ if (extIdx > 0) {
+ return filename.substr(extIdx, filename.length - extIdx);
+ }
+ };
+ qq.getFilename = function(blobOrFileInput) {
+ if (qq.isInput(blobOrFileInput)) {
+ return blobOrFileInput.value.replace(/.*(\/|\\)/, "");
+ } else if (qq.isFile(blobOrFileInput)) {
+ if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {
+ return blobOrFileInput.fileName;
+ }
+ }
+ return blobOrFileInput.name;
+ };
+ qq.DisposeSupport = function() {
+ var disposers = [];
+ return {
+ dispose: function() {
+ var disposer;
+ do {
+ disposer = disposers.shift();
+ if (disposer) {
+ disposer();
+ }
+ } while (disposer);
+ },
+ attach: function() {
+ var args = arguments;
+ this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));
+ },
+ addDisposer: function(disposeFunction) {
+ disposers.push(disposeFunction);
+ }
+ };
+ };
+ })();
+ (function() {
+ "use strict";
+ if (typeof define === "function" && define.amd) {
+ define(function() {
+ return qq;
+ });
+ } else if (typeof module !== "undefined" && module.exports) {
+ module.exports = qq;
+ } else {
+ global.qq = qq;
+ }
+ })();
+ (function() {
+ "use strict";
+ qq.Error = function(message) {
+ this.message = "[Fine Uploader " + qq.version + "] " + message;
+ };
+ qq.Error.prototype = new Error();
+ })();
+ qq.version = "5.13.0";
+ qq.supportedFeatures = function() {
+ "use strict";
+ var supportsUploading, supportsUploadingBlobs, supportsFileDrop, supportsAjaxFileUploading, supportsFolderDrop, supportsChunking, supportsResume, supportsUploadViaPaste, supportsUploadCors, supportsDeleteFileXdr, supportsDeleteFileCorsXhr, supportsDeleteFileCors, supportsFolderSelection, supportsImagePreviews, supportsUploadProgress;
+ function testSupportsFileInputElement() {
+ var supported = true, tempInput;
+ try {
+ tempInput = document.createElement("input");
+ tempInput.type = "file";
+ qq(tempInput).hide();
+ if (tempInput.disabled) {
+ supported = false;
+ }
+ } catch (ex) {
+ supported = false;
+ }
+ return supported;
+ }
+ function isChrome21OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/) !== undefined;
+ }
+ function isChrome14OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/) !== undefined;
+ }
+ function isCrossOriginXhrSupported() {
+ if (window.XMLHttpRequest) {
+ var xhr = qq.createXhrInstance();
+ return xhr.withCredentials !== undefined;
+ }
+ return false;
+ }
+ function isXdrSupported() {
+ return window.XDomainRequest !== undefined;
+ }
+ function isCrossOriginAjaxSupported() {
+ if (isCrossOriginXhrSupported()) {
+ return true;
+ }
+ return isXdrSupported();
+ }
+ function isFolderSelectionSupported() {
+ return document.createElement("input").webkitdirectory !== undefined;
+ }
+ function isLocalStorageSupported() {
+ try {
+ return !!window.localStorage && qq.isFunction(window.localStorage.setItem);
+ } catch (error) {
+ return false;
+ }
+ }
+ function isDragAndDropSupported() {
+ var span = document.createElement("span");
+ return ("draggable" in span || "ondragstart" in span && "ondrop" in span) && !qq.android() && !qq.ios();
+ }
+ supportsUploading = testSupportsFileInputElement();
+ supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();
+ supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();
+ supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();
+ supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();
+ supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();
+ supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();
+ supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();
+ supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);
+ supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();
+ supportsDeleteFileXdr = isXdrSupported();
+ supportsDeleteFileCors = isCrossOriginAjaxSupported();
+ supportsFolderSelection = isFolderSelectionSupported();
+ supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;
+ supportsUploadProgress = function() {
+ if (supportsAjaxFileUploading) {
+ return !qq.androidStock() && !qq.iosChrome();
+ }
+ return false;
+ }();
+ return {
+ ajaxUploading: supportsAjaxFileUploading,
+ blobUploading: supportsUploadingBlobs,
+ canDetermineSize: supportsAjaxFileUploading,
+ chunking: supportsChunking,
+ deleteFileCors: supportsDeleteFileCors,
+ deleteFileCorsXdr: supportsDeleteFileXdr,
+ deleteFileCorsXhr: supportsDeleteFileCorsXhr,
+ dialogElement: !!window.HTMLDialogElement,
+ fileDrop: supportsFileDrop,
+ folderDrop: supportsFolderDrop,
+ folderSelection: supportsFolderSelection,
+ imagePreviews: supportsImagePreviews,
+ imageValidation: supportsImagePreviews,
+ itemSizeValidation: supportsAjaxFileUploading,
+ pause: supportsChunking,
+ progressBar: supportsUploadProgress,
+ resume: supportsResume,
+ scaling: supportsImagePreviews && supportsUploadingBlobs,
+ tiffPreviews: qq.safari(),
+ unlimitedScaledImageSize: !qq.ios(),
+ uploading: supportsUploading,
+ uploadCors: supportsUploadCors,
+ uploadCustomHeaders: supportsAjaxFileUploading,
+ uploadNonMultipart: supportsAjaxFileUploading,
+ uploadViaPaste: supportsUploadViaPaste
+ };
+ }();
+ qq.isGenericPromise = function(maybePromise) {
+ "use strict";
+ return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));
+ };
+ qq.Promise = function() {
+ "use strict";
+ var successArgs, failureArgs, successCallbacks = [], failureCallbacks = [], doneCallbacks = [], state = 0;
+ qq.extend(this, {
+ then: function(onSuccess, onFailure) {
+ if (state === 0) {
+ if (onSuccess) {
+ successCallbacks.push(onSuccess);
+ }
+ if (onFailure) {
+ failureCallbacks.push(onFailure);
+ }
+ } else if (state === -1) {
+ onFailure && onFailure.apply(null, failureArgs);
+ } else if (onSuccess) {
+ onSuccess.apply(null, successArgs);
+ }
+ return this;
+ },
+ done: function(callback) {
+ if (state === 0) {
+ doneCallbacks.push(callback);
+ } else {
+ callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);
+ }
+ return this;
+ },
+ success: function() {
+ state = 1;
+ successArgs = arguments;
+ if (successCallbacks.length) {
+ qq.each(successCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ return this;
+ },
+ failure: function() {
+ state = -1;
+ failureArgs = arguments;
+ if (failureCallbacks.length) {
+ qq.each(failureCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ return this;
+ }
+ });
+ };
+ qq.BlobProxy = function(referenceBlob, onCreate) {
+ "use strict";
+ qq.extend(this, {
+ referenceBlob: referenceBlob,
+ create: function() {
+ return onCreate(referenceBlob);
+ }
+ });
+ };
+ qq.UploadButton = function(o) {
+ "use strict";
+ var self = this, disposeSupport = new qq.DisposeSupport(), options = {
+ acceptFiles: null,
+ element: null,
+ focusClass: "qq-upload-button-focus",
+ folders: false,
+ hoverClass: "qq-upload-button-hover",
+ ios8BrowserCrashWorkaround: false,
+ multiple: false,
+ name: "qqfile",
+ onChange: function(input) {},
+ title: null
+ }, input, buttonId;
+ qq.extend(options, o);
+ buttonId = qq.getUniqueId();
+ function createInput() {
+ var input = document.createElement("input");
+ input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);
+ input.setAttribute("title", options.title);
+ self.setMultiple(options.multiple, input);
+ if (options.folders && qq.supportedFeatures.folderSelection) {
+ input.setAttribute("webkitdirectory", "");
+ }
+ if (options.acceptFiles) {
+ input.setAttribute("accept", options.acceptFiles);
+ }
+ input.setAttribute("type", "file");
+ input.setAttribute("name", options.name);
+ qq(input).css({
+ position: "absolute",
+ right: 0,
+ top: 0,
+ fontFamily: "Arial",
+ fontSize: qq.ie() && !qq.ie8() ? "3500px" : "118px",
+ margin: 0,
+ padding: 0,
+ cursor: "pointer",
+ opacity: 0
+ });
+ !qq.ie7() && qq(input).css({
+ height: "100%"
+ });
+ options.element.appendChild(input);
+ disposeSupport.attach(input, "change", function() {
+ options.onChange(input);
+ });
+ disposeSupport.attach(input, "mouseover", function() {
+ qq(options.element).addClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "mouseout", function() {
+ qq(options.element).removeClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "focus", function() {
+ qq(options.element).addClass(options.focusClass);
+ });
+ disposeSupport.attach(input, "blur", function() {
+ qq(options.element).removeClass(options.focusClass);
+ });
+ return input;
+ }
+ qq(options.element).css({
+ position: "relative",
+ overflow: "hidden",
+ direction: "ltr"
+ });
+ qq.extend(this, {
+ getInput: function() {
+ return input;
+ },
+ getButtonId: function() {
+ return buttonId;
+ },
+ setMultiple: function(isMultiple, optInput) {
+ var input = optInput || this.getInput();
+ if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {
+ input.setAttribute("multiple", "");
+ } else {
+ if (isMultiple) {
+ input.setAttribute("multiple", "");
+ } else {
+ input.removeAttribute("multiple");
+ }
+ }
+ },
+ setAcceptFiles: function(acceptFiles) {
+ if (acceptFiles !== options.acceptFiles) {
+ input.setAttribute("accept", acceptFiles);
+ }
+ },
+ reset: function() {
+ if (input.parentNode) {
+ qq(input).remove();
+ }
+ qq(options.element).removeClass(options.focusClass);
+ input = null;
+ input = createInput();
+ }
+ });
+ input = createInput();
+ };
+ qq.UploadButton.BUTTON_ID_ATTR_NAME = "qq-button-id";
+ qq.UploadData = function(uploaderProxy) {
+ "use strict";
+ var data = [], byUuid = {}, byStatus = {}, byProxyGroupId = {}, byBatchId = {};
+ function getDataByIds(idOrIds) {
+ if (qq.isArray(idOrIds)) {
+ var entries = [];
+ qq.each(idOrIds, function(idx, id) {
+ entries.push(data[id]);
+ });
+ return entries;
+ }
+ return data[idOrIds];
+ }
+ function getDataByUuids(uuids) {
+ if (qq.isArray(uuids)) {
+ var entries = [];
+ qq.each(uuids, function(idx, uuid) {
+ entries.push(data[byUuid[uuid]]);
+ });
+ return entries;
+ }
+ return data[byUuid[uuids]];
+ }
+ function getDataByStatus(status) {
+ var statusResults = [], statuses = [].concat(status);
+ qq.each(statuses, function(index, statusEnum) {
+ var statusResultIndexes = byStatus[statusEnum];
+ if (statusResultIndexes !== undefined) {
+ qq.each(statusResultIndexes, function(i, dataIndex) {
+ statusResults.push(data[dataIndex]);
+ });
+ }
+ });
+ return statusResults;
+ }
+ qq.extend(this, {
+ addFile: function(spec) {
+ var status = spec.status || qq.status.SUBMITTING, id = data.push({
+ name: spec.name,
+ originalName: spec.name,
+ uuid: spec.uuid,
+ size: spec.size == null ? -1 : spec.size,
+ status: status
+ }) - 1;
+ if (spec.batchId) {
+ data[id].batchId = spec.batchId;
+ if (byBatchId[spec.batchId] === undefined) {
+ byBatchId[spec.batchId] = [];
+ }
+ byBatchId[spec.batchId].push(id);
+ }
+ if (spec.proxyGroupId) {
+ data[id].proxyGroupId = spec.proxyGroupId;
+ if (byProxyGroupId[spec.proxyGroupId] === undefined) {
+ byProxyGroupId[spec.proxyGroupId] = [];
+ }
+ byProxyGroupId[spec.proxyGroupId].push(id);
+ }
+ data[id].id = id;
+ byUuid[spec.uuid] = id;
+ if (byStatus[status] === undefined) {
+ byStatus[status] = [];
+ }
+ byStatus[status].push(id);
+ uploaderProxy.onStatusChange(id, null, status);
+ return id;
+ },
+ retrieve: function(optionalFilter) {
+ if (qq.isObject(optionalFilter) && data.length) {
+ if (optionalFilter.id !== undefined) {
+ return getDataByIds(optionalFilter.id);
+ } else if (optionalFilter.uuid !== undefined) {
+ return getDataByUuids(optionalFilter.uuid);
+ } else if (optionalFilter.status) {
+ return getDataByStatus(optionalFilter.status);
+ }
+ } else {
+ return qq.extend([], data, true);
+ }
+ },
+ reset: function() {
+ data = [];
+ byUuid = {};
+ byStatus = {};
+ byBatchId = {};
+ },
+ setStatus: function(id, newStatus) {
+ var oldStatus = data[id].status, byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);
+ byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);
+ data[id].status = newStatus;
+ if (byStatus[newStatus] === undefined) {
+ byStatus[newStatus] = [];
+ }
+ byStatus[newStatus].push(id);
+ uploaderProxy.onStatusChange(id, oldStatus, newStatus);
+ },
+ uuidChanged: function(id, newUuid) {
+ var oldUuid = data[id].uuid;
+ data[id].uuid = newUuid;
+ byUuid[newUuid] = id;
+ delete byUuid[oldUuid];
+ },
+ updateName: function(id, newName) {
+ data[id].name = newName;
+ },
+ updateSize: function(id, newSize) {
+ data[id].size = newSize;
+ },
+ setParentId: function(targetId, parentId) {
+ data[targetId].parentId = parentId;
+ },
+ getIdsInProxyGroup: function(id) {
+ var proxyGroupId = data[id].proxyGroupId;
+ if (proxyGroupId) {
+ return byProxyGroupId[proxyGroupId];
+ }
+ return [];
+ },
+ getIdsInBatch: function(id) {
+ var batchId = data[id].batchId;
+ return byBatchId[batchId];
+ }
+ });
+ };
+ qq.status = {
+ SUBMITTING: "submitting",
+ SUBMITTED: "submitted",
+ REJECTED: "rejected",
+ QUEUED: "queued",
+ CANCELED: "canceled",
+ PAUSED: "paused",
+ UPLOADING: "uploading",
+ UPLOAD_RETRYING: "retrying upload",
+ UPLOAD_SUCCESSFUL: "upload successful",
+ UPLOAD_FAILED: "upload failed",
+ DELETE_FAILED: "delete failed",
+ DELETING: "deleting",
+ DELETED: "deleted"
+ };
+ (function() {
+ "use strict";
+ qq.basePublicApi = {
+ addBlobs: function(blobDataOrArray, params, endpoint) {
+ this.addFiles(blobDataOrArray, params, endpoint);
+ },
+ addInitialFiles: function(cannedFileList) {
+ var self = this;
+ qq.each(cannedFileList, function(index, cannedFile) {
+ self._addCannedFile(cannedFile);
+ });
+ },
+ addFiles: function(data, params, endpoint) {
+ this._maybeHandleIos8SafariWorkaround();
+ var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId, processBlob = qq.bind(function(blob) {
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName
+ }, batchId, verifiedFiles);
+ }, this), processBlobData = qq.bind(function(blobData) {
+ this._handleNewFile(blobData, batchId, verifiedFiles);
+ }, this), processCanvas = qq.bind(function(canvas) {
+ var blob = qq.canvasToBlob(canvas);
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName + ".png"
+ }, batchId, verifiedFiles);
+ }, this), processCanvasData = qq.bind(function(canvasData) {
+ var normalizedQuality = canvasData.quality && canvasData.quality / 100, blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);
+ this._handleNewFile({
+ blob: blob,
+ name: canvasData.name
+ }, batchId, verifiedFiles);
+ }, this), processFileOrInput = qq.bind(function(fileOrInput) {
+ if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {
+ var files = Array.prototype.slice.call(fileOrInput.files), self = this;
+ qq.each(files, function(idx, file) {
+ self._handleNewFile(file, batchId, verifiedFiles);
+ });
+ } else {
+ this._handleNewFile(fileOrInput, batchId, verifiedFiles);
+ }
+ }, this), normalizeData = function() {
+ if (qq.isFileList(data)) {
+ data = Array.prototype.slice.call(data);
+ }
+ data = [].concat(data);
+ }, self = this, verifiedFiles = [];
+ this._currentBatchId = batchId;
+ if (data) {
+ normalizeData();
+ qq.each(data, function(idx, fileContainer) {
+ if (qq.isFileOrInput(fileContainer)) {
+ processFileOrInput(fileContainer);
+ } else if (qq.isBlob(fileContainer)) {
+ processBlob(fileContainer);
+ } else if (qq.isObject(fileContainer)) {
+ if (fileContainer.blob && fileContainer.name) {
+ processBlobData(fileContainer);
+ } else if (fileContainer.canvas && fileContainer.name) {
+ processCanvasData(fileContainer);
+ }
+ } else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === "canvas") {
+ processCanvas(fileContainer);
+ } else {
+ self.log(fileContainer + " is not a valid file container! Ignoring!", "warn");
+ }
+ });
+ this.log("Received " + verifiedFiles.length + " files.");
+ this._prepareItemsForUpload(verifiedFiles, params, endpoint);
+ }
+ },
+ cancel: function(id) {
+ this._handler.cancel(id);
+ },
+ cancelAll: function() {
+ var storedIdsCopy = [], self = this;
+ qq.extend(storedIdsCopy, this._storedIds);
+ qq.each(storedIdsCopy, function(idx, storedFileId) {
+ self.cancel(storedFileId);
+ });
+ this._handler.cancelAll();
+ },
+ clearStoredFiles: function() {
+ this._storedIds = [];
+ },
+ continueUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (uploadData.status === qq.status.PAUSED) {
+ this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.", id, this.getName(id)));
+ this._uploadFile(id);
+ return true;
+ } else {
+ this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ deleteFile: function(id) {
+ return this._onSubmitDelete(id);
+ },
+ doesExist: function(fileOrBlobId) {
+ return this._handler.isValid(fileOrBlobId);
+ },
+ drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {
+ var promiseToReturn = new qq.Promise(), fileOrUrl, options;
+ if (this._imageGenerator) {
+ fileOrUrl = this._thumbnailUrls[fileId];
+ options = {
+ customResizeFunction: customResizeFunction,
+ maxSize: maxSize > 0 ? maxSize : null,
+ scale: maxSize > 0
+ };
+ if (!fromServer && qq.supportedFeatures.imagePreviews) {
+ fileOrUrl = this.getFile(fileId);
+ }
+ if (fileOrUrl == null) {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "File or URL not found."
+ });
+ } else {
+ this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(function success(modifiedContainer) {
+ promiseToReturn.success(modifiedContainer);
+ }, function failure(container, reason) {
+ promiseToReturn.failure({
+ container: container,
+ error: reason || "Problem generating thumbnail"
+ });
+ });
+ }
+ } else {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "Missing image generator module"
+ });
+ }
+ return promiseToReturn;
+ },
+ getButton: function(fileId) {
+ return this._getButton(this._buttonIdsForFileIds[fileId]);
+ },
+ getEndpoint: function(fileId) {
+ return this._endpointStore.get(fileId);
+ },
+ getFile: function(fileOrBlobId) {
+ return this._handler.getFile(fileOrBlobId) || null;
+ },
+ getInProgress: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED ]
+ }).length;
+ },
+ getName: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).name;
+ },
+ getParentId: function(id) {
+ var uploadDataEntry = this.getUploads({
+ id: id
+ }), parentId = null;
+ if (uploadDataEntry) {
+ if (uploadDataEntry.parentId !== undefined) {
+ parentId = uploadDataEntry.parentId;
+ }
+ }
+ return parentId;
+ },
+ getResumableFilesData: function() {
+ return this._handler.getResumableFilesData();
+ },
+ getSize: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).size;
+ },
+ getNetUploads: function() {
+ return this._netUploaded;
+ },
+ getRemainingAllowedItems: function() {
+ var allowedItems = this._currentItemLimit;
+ if (allowedItems > 0) {
+ return allowedItems - this._netUploadedOrQueued;
+ }
+ return null;
+ },
+ getUploads: function(optionalFilter) {
+ return this._uploadData.retrieve(optionalFilter);
+ },
+ getUuid: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).uuid;
+ },
+ log: function(str, level) {
+ if (this._options.debug && (!level || level === "info")) {
+ qq.log("[Fine Uploader " + qq.version + "] " + str);
+ } else if (level && level !== "info") {
+ qq.log("[Fine Uploader " + qq.version + "] " + str, level);
+ }
+ },
+ pauseUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (qq.indexOf([ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING ], uploadData.status) >= 0) {
+ if (this._handler.pause(id)) {
+ this._uploadData.setStatus(id, qq.status.PAUSED);
+ return true;
+ } else {
+ this.log(qq.format("Unable to pause file ID {} ({}).", id, this.getName(id)), "error");
+ }
+ } else {
+ this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ reset: function() {
+ this.log("Resetting uploader...");
+ this._handler.reset();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ this._paramsStore.reset();
+ this._endpointStore.reset();
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData.reset();
+ this._buttonIdsForFileIds = [];
+ this._pasteHandler && this._pasteHandler.reset();
+ this._options.session.refreshOnReset && this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._totalProgress && this._totalProgress.reset();
+ },
+ retry: function(id) {
+ return this._manualRetry(id);
+ },
+ scaleImage: function(id, specs) {
+ var self = this;
+ return qq.Scaler.prototype.scaleImage(id, specs, {
+ log: qq.bind(self.log, self),
+ getFile: qq.bind(self.getFile, self),
+ uploadData: self._uploadData
+ });
+ },
+ setCustomHeaders: function(headers, id) {
+ this._customHeadersStore.set(headers, id);
+ },
+ setDeleteFileCustomHeaders: function(headers, id) {
+ this._deleteFileCustomHeadersStore.set(headers, id);
+ },
+ setDeleteFileEndpoint: function(endpoint, id) {
+ this._deleteFileEndpointStore.set(endpoint, id);
+ },
+ setDeleteFileParams: function(params, id) {
+ this._deleteFileParamsStore.set(params, id);
+ },
+ setEndpoint: function(endpoint, id) {
+ this._endpointStore.set(endpoint, id);
+ },
+ setForm: function(elementOrId) {
+ this._updateFormSupportAndParams(elementOrId);
+ },
+ setItemLimit: function(newItemLimit) {
+ this._currentItemLimit = newItemLimit;
+ },
+ setName: function(id, newName) {
+ this._uploadData.updateName(id, newName);
+ },
+ setParams: function(params, id) {
+ this._paramsStore.set(params, id);
+ },
+ setUuid: function(id, newUuid) {
+ return this._uploadData.uuidChanged(id, newUuid);
+ },
+ uploadStoredFiles: function() {
+ if (this._storedIds.length === 0) {
+ this._itemError("noFilesError");
+ } else {
+ this._uploadStoredFiles();
+ }
+ }
+ };
+ qq.basePrivateApi = {
+ _addCannedFile: function(sessionData) {
+ var id = this._uploadData.addFile({
+ uuid: sessionData.uuid,
+ name: sessionData.name,
+ size: sessionData.size,
+ status: qq.status.UPLOAD_SUCCESSFUL
+ });
+ sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);
+ sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);
+ if (sessionData.thumbnailUrl) {
+ this._thumbnailUrls[id] = sessionData.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._netUploadedOrQueued++;
+ return id;
+ },
+ _annotateWithButtonId: function(file, associatedInput) {
+ if (qq.isFile(file)) {
+ file.qqButtonId = this._getButtonId(associatedInput);
+ }
+ },
+ _batchError: function(message) {
+ this._options.callbacks.onError(null, null, message, undefined);
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return new qq.DeleteFileAjaxRequester({
+ method: this._options.deleteFile.method.toUpperCase(),
+ maxConnections: this._options.maxConnections,
+ uuidParamName: this._options.request.uuidName,
+ customHeaders: this._deleteFileCustomHeadersStore,
+ paramsStore: this._deleteFileParamsStore,
+ endpointStore: this._deleteFileEndpointStore,
+ cors: this._options.cors,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ });
+ },
+ _createPasteHandler: function() {
+ var self = this;
+ return new qq.PasteSupport({
+ targetElement: this._options.paste.targetElement,
+ callbacks: {
+ log: qq.bind(self.log, self),
+ pasteReceived: function(blob) {
+ self._handleCheckedCallback({
+ name: "onPasteReceived",
+ callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),
+ onSuccess: qq.bind(self._handlePasteSuccess, self, blob),
+ identifier: "pasted image"
+ });
+ }
+ }
+ });
+ },
+ _createStore: function(initialValue, _readOnlyValues_) {
+ var store = {}, catchall = initialValue, perIdReadOnlyValues = {}, readOnlyValues = _readOnlyValues_, copy = function(orig) {
+ if (qq.isObject(orig)) {
+ return qq.extend({}, orig);
+ }
+ return orig;
+ }, getReadOnlyValues = function() {
+ if (qq.isFunction(readOnlyValues)) {
+ return readOnlyValues();
+ }
+ return readOnlyValues;
+ }, includeReadOnlyValues = function(id, existing) {
+ if (readOnlyValues && qq.isObject(existing)) {
+ qq.extend(existing, getReadOnlyValues());
+ }
+ if (perIdReadOnlyValues[id]) {
+ qq.extend(existing, perIdReadOnlyValues[id]);
+ }
+ };
+ return {
+ set: function(val, id) {
+ if (id == null) {
+ store = {};
+ catchall = copy(val);
+ } else {
+ store[id] = copy(val);
+ }
+ },
+ get: function(id) {
+ var values;
+ if (id != null && store[id]) {
+ values = store[id];
+ } else {
+ values = copy(catchall);
+ }
+ includeReadOnlyValues(id, values);
+ return copy(values);
+ },
+ addReadOnly: function(id, values) {
+ if (qq.isObject(store)) {
+ if (id === null) {
+ if (qq.isFunction(values)) {
+ readOnlyValues = values;
+ } else {
+ readOnlyValues = readOnlyValues || {};
+ qq.extend(readOnlyValues, values);
+ }
+ } else {
+ perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};
+ qq.extend(perIdReadOnlyValues[id], values);
+ }
+ }
+ },
+ remove: function(fileId) {
+ return delete store[fileId];
+ },
+ reset: function() {
+ store = {};
+ perIdReadOnlyValues = {};
+ catchall = initialValue;
+ }
+ };
+ },
+ _createUploadDataTracker: function() {
+ var self = this;
+ return new qq.UploadData({
+ getName: function(id) {
+ return self.getName(id);
+ },
+ getUuid: function(id) {
+ return self.getUuid(id);
+ },
+ getSize: function(id) {
+ return self.getSize(id);
+ },
+ onStatusChange: function(id, oldStatus, newStatus) {
+ self._onUploadStatusChange(id, oldStatus, newStatus);
+ self._options.callbacks.onStatusChange(id, oldStatus, newStatus);
+ self._maybeAllComplete(id, newStatus);
+ if (self._totalProgress) {
+ setTimeout(function() {
+ self._totalProgress.onStatusChange(id, oldStatus, newStatus);
+ }, 0);
+ }
+ }
+ });
+ },
+ _createUploadButton: function(spec) {
+ var self = this, acceptFiles = spec.accept || this._options.validation.acceptFiles, allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions, button;
+ function allowMultiple() {
+ if (qq.supportedFeatures.ajaxUploading) {
+ if (self._options.workarounds.iosEmptyVideos && qq.ios() && !qq.ios6() && self._isAllowedExtension(allowedExtensions, ".mov")) {
+ return false;
+ }
+ if (spec.multiple === undefined) {
+ return self._options.multiple;
+ }
+ return spec.multiple;
+ }
+ return false;
+ }
+ button = new qq.UploadButton({
+ acceptFiles: acceptFiles,
+ element: spec.element,
+ focusClass: this._options.classes.buttonFocus,
+ folders: spec.folders,
+ hoverClass: this._options.classes.buttonHover,
+ ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,
+ multiple: allowMultiple(),
+ name: this._options.request.inputName,
+ onChange: function(input) {
+ self._onInputChange(input);
+ },
+ title: spec.title == null ? this._options.text.fileInputTitle : spec.title
+ });
+ this._disposeSupport.addDisposer(function() {
+ button.dispose();
+ });
+ self._buttons.push(button);
+ return button;
+ },
+ _createUploadHandler: function(additionalOptions, namespace) {
+ var self = this, lastOnProgress = {}, options = {
+ debug: this._options.debug,
+ maxConnections: this._options.maxConnections,
+ cors: this._options.cors,
+ paramsStore: this._paramsStore,
+ endpointStore: this._endpointStore,
+ chunking: this._options.chunking,
+ resume: this._options.resume,
+ blobs: this._options.blobs,
+ log: qq.bind(self.log, self),
+ preventRetryParam: this._options.retry.preventRetryResponseProperty,
+ onProgress: function(id, name, loaded, total) {
+ if (loaded < 0 || total < 0) {
+ return;
+ }
+ if (lastOnProgress[id]) {
+ if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ } else {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ lastOnProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onComplete: function(id, name, result, xhr) {
+ delete lastOnProgress[id];
+ var status = self.getUploads({
+ id: id
+ }).status, retVal;
+ if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {
+ return;
+ }
+ retVal = self._onComplete(id, name, result, xhr);
+ if (retVal instanceof qq.Promise) {
+ retVal.done(function() {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ });
+ } else {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ }
+ },
+ onCancel: function(id, name, cancelFinalizationEffort) {
+ var promise = new qq.Promise();
+ self._handleCheckedCallback({
+ name: "onCancel",
+ callback: qq.bind(self._options.callbacks.onCancel, self, id, name),
+ onFailure: promise.failure,
+ onSuccess: function() {
+ cancelFinalizationEffort.then(function() {
+ self._onCancel(id, name);
+ });
+ promise.success();
+ },
+ identifier: id
+ });
+ return promise;
+ },
+ onUploadPrep: qq.bind(this._onUploadPrep, this),
+ onUpload: function(id, name) {
+ self._onUpload(id, name);
+ self._options.callbacks.onUpload(id, name);
+ },
+ onUploadChunk: function(id, name, chunkData) {
+ self._onUploadChunk(id, chunkData);
+ self._options.callbacks.onUploadChunk(id, name, chunkData);
+ },
+ onUploadChunkSuccess: function(id, chunkData, result, xhr) {
+ self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);
+ },
+ onResume: function(id, name, chunkData) {
+ return self._options.callbacks.onResume(id, name, chunkData);
+ },
+ onAutoRetry: function(id, name, responseJSON, xhr) {
+ return self._onAutoRetry.apply(self, arguments);
+ },
+ onUuidChanged: function(id, newUuid) {
+ self.log("Server requested UUID change from '" + self.getUuid(id) + "' to '" + newUuid + "'");
+ self.setUuid(id, newUuid);
+ },
+ getName: qq.bind(self.getName, self),
+ getUuid: qq.bind(self.getUuid, self),
+ getSize: qq.bind(self.getSize, self),
+ setSize: qq.bind(self._setSize, self),
+ getDataByUuid: function(uuid) {
+ return self.getUploads({
+ uuid: uuid
+ });
+ },
+ isQueued: function(id) {
+ var status = self.getUploads({
+ id: id
+ }).status;
+ return status === qq.status.QUEUED || status === qq.status.SUBMITTED || status === qq.status.UPLOAD_RETRYING || status === qq.status.PAUSED;
+ },
+ getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,
+ getIdsInBatch: self._uploadData.getIdsInBatch
+ };
+ qq.each(this._options.request, function(prop, val) {
+ options[prop] = val;
+ });
+ options.customHeaders = this._customHeadersStore;
+ if (additionalOptions) {
+ qq.each(additionalOptions, function(key, val) {
+ options[key] = val;
+ });
+ }
+ return new qq.UploadHandlerController(options, namespace);
+ },
+ _fileOrBlobRejected: function(id) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.REJECTED);
+ },
+ _formatSize: function(bytes) {
+ if (bytes === 0) {
+ return bytes + this._options.text.sizeSymbols[0];
+ }
+ var i = -1;
+ do {
+ bytes = bytes / 1e3;
+ i++;
+ } while (bytes > 999);
+ return Math.max(bytes, .1).toFixed(1) + this._options.text.sizeSymbols[i];
+ },
+ _generateExtraButtonSpecs: function() {
+ var self = this;
+ this._extraButtonSpecs = {};
+ qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {
+ var multiple = extraButtonOptionEntry.multiple, validation = qq.extend({}, self._options.validation, true), extraButtonSpec = qq.extend({}, extraButtonOptionEntry);
+ if (multiple === undefined) {
+ multiple = self._options.multiple;
+ }
+ if (extraButtonSpec.validation) {
+ qq.extend(validation, extraButtonOptionEntry.validation, true);
+ }
+ qq.extend(extraButtonSpec, {
+ multiple: multiple,
+ validation: validation
+ }, true);
+ self._initExtraButton(extraButtonSpec);
+ });
+ },
+ _getButton: function(buttonId) {
+ var extraButtonsSpec = this._extraButtonSpecs[buttonId];
+ if (extraButtonsSpec) {
+ return extraButtonsSpec.element;
+ } else if (buttonId === this._defaultButtonId) {
+ return this._options.button;
+ }
+ },
+ _getButtonId: function(buttonOrFileInputOrFile) {
+ var inputs, fileInput, fileBlobOrInput = buttonOrFileInputOrFile;
+ if (fileBlobOrInput instanceof qq.BlobProxy) {
+ fileBlobOrInput = fileBlobOrInput.referenceBlob;
+ }
+ if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {
+ if (qq.isFile(fileBlobOrInput)) {
+ return fileBlobOrInput.qqButtonId;
+ } else if (fileBlobOrInput.tagName.toLowerCase() === "input" && fileBlobOrInput.type.toLowerCase() === "file") {
+ return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ inputs = fileBlobOrInput.getElementsByTagName("input");
+ qq.each(inputs, function(idx, input) {
+ if (input.getAttribute("type") === "file") {
+ fileInput = input;
+ return false;
+ }
+ });
+ if (fileInput) {
+ return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ }
+ },
+ _getNotFinished: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED, qq.status.SUBMITTING, qq.status.SUBMITTED, qq.status.PAUSED ]
+ }).length;
+ },
+ _getValidationBase: function(buttonId) {
+ var extraButtonSpec = this._extraButtonSpecs[buttonId];
+ return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;
+ },
+ _getValidationDescriptor: function(fileWrapper) {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return {
+ name: qq.getFilename(fileWrapper.file.referenceBlob),
+ size: fileWrapper.file.referenceBlob.size
+ };
+ }
+ return {
+ name: this.getUploads({
+ id: fileWrapper.id
+ }).name,
+ size: this.getUploads({
+ id: fileWrapper.id
+ }).size
+ };
+ },
+ _getValidationDescriptors: function(fileWrappers) {
+ var self = this, fileDescriptors = [];
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ fileDescriptors.push(self._getValidationDescriptor(fileWrapper));
+ });
+ return fileDescriptors;
+ },
+ _handleCameraAccess: function() {
+ if (this._options.camera.ios && qq.ios()) {
+ var acceptIosCamera = "image/*;capture=camera", button = this._options.camera.button, buttonId = button ? this._getButtonId(button) : this._defaultButtonId, optionRoot = this._options;
+ if (buttonId && buttonId !== this._defaultButtonId) {
+ optionRoot = this._extraButtonSpecs[buttonId];
+ }
+ optionRoot.multiple = false;
+ if (optionRoot.validation.acceptFiles === null) {
+ optionRoot.validation.acceptFiles = acceptIosCamera;
+ } else {
+ optionRoot.validation.acceptFiles += "," + acceptIosCamera;
+ }
+ qq.each(this._buttons, function(idx, button) {
+ if (button.getButtonId() === buttonId) {
+ button.setMultiple(optionRoot.multiple);
+ button.setAcceptFiles(optionRoot.acceptFiles);
+ return false;
+ }
+ });
+ }
+ },
+ _handleCheckedCallback: function(details) {
+ var self = this, callbackRetVal = details.callback();
+ if (qq.isGenericPromise(callbackRetVal)) {
+ this.log(details.name + " - waiting for " + details.name + " promise to be fulfilled for " + details.identifier);
+ return callbackRetVal.then(function(successParam) {
+ self.log(details.name + " promise success for " + details.identifier);
+ details.onSuccess(successParam);
+ }, function() {
+ if (details.onFailure) {
+ self.log(details.name + " promise failure for " + details.identifier);
+ details.onFailure();
+ } else {
+ self.log(details.name + " promise failure for " + details.identifier);
+ }
+ });
+ }
+ if (callbackRetVal !== false) {
+ details.onSuccess(callbackRetVal);
+ } else {
+ if (details.onFailure) {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Invoking failure callback.");
+ details.onFailure();
+ } else {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Will not proceed.");
+ }
+ }
+ return callbackRetVal;
+ },
+ _handleNewFile: function(file, batchId, newFileWrapperList) {
+ var self = this, uuid = qq.getUniqueId(), size = -1, name = qq.getFilename(file), actualFile = file.blob || file, handler = this._customNewFileHandler ? this._customNewFileHandler : qq.bind(self._handleNewFileGeneric, self);
+ if (!qq.isInput(actualFile) && actualFile.size >= 0) {
+ size = actualFile.size;
+ }
+ handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {
+ uploadData: self._uploadData,
+ paramsStore: self._paramsStore,
+ addFileToHandler: function(id, file) {
+ self._handler.add(id, file);
+ self._netUploadedOrQueued++;
+ self._trackButton(id);
+ }
+ });
+ },
+ _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {
+ var id = this._uploadData.addFile({
+ uuid: uuid,
+ name: name,
+ size: size,
+ batchId: batchId
+ });
+ this._handler.add(id, file);
+ this._trackButton(id);
+ this._netUploadedOrQueued++;
+ fileList.push({
+ id: id,
+ file: file
+ });
+ },
+ _handlePasteSuccess: function(blob, extSuppliedName) {
+ var extension = blob.type.split("/")[1], name = extSuppliedName;
+ if (name == null) {
+ name = this._options.paste.defaultName;
+ }
+ name += "." + extension;
+ this.addFiles({
+ name: name,
+ blob: blob
+ });
+ },
+ _initExtraButton: function(spec) {
+ var button = this._createUploadButton({
+ accept: spec.validation.acceptFiles,
+ allowedExtensions: spec.validation.allowedExtensions,
+ element: spec.element,
+ folders: spec.folders,
+ multiple: spec.multiple,
+ title: spec.fileInputTitle
+ });
+ this._extraButtonSpecs[button.getButtonId()] = spec;
+ },
+ _initFormSupportAndParams: function() {
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore = this._createStore(this._options.request.params, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this._options.request.endpoint = this._formSupport.newEndpoint;
+ }
+ } else {
+ this._paramsStore = this._createStore(this._options.request.params);
+ }
+ },
+ _isDeletePossible: function() {
+ if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {
+ return false;
+ }
+ if (this._options.cors.expected) {
+ if (qq.supportedFeatures.deleteFileCorsXhr) {
+ return true;
+ }
+ if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ },
+ _isAllowedExtension: function(allowed, fileName) {
+ var valid = false;
+ if (!allowed.length) {
+ return true;
+ }
+ qq.each(allowed, function(idx, allowedExt) {
+ if (qq.isString(allowedExt)) {
+ var extRegex = new RegExp("\\." + allowedExt + "$", "i");
+ if (fileName.match(extRegex) != null) {
+ valid = true;
+ return false;
+ }
+ }
+ });
+ return valid;
+ },
+ _itemError: function(code, maybeNameOrNames, item) {
+ var message = this._options.messages[code], allowedExtensions = [], names = [].concat(maybeNameOrNames), name = names[0], buttonId = this._getButtonId(item), validationBase = this._getValidationBase(buttonId), extensionsForMessage, placeholderMatch;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {
+ if (qq.isString(allowedExtension)) {
+ allowedExtensions.push(allowedExtension);
+ }
+ });
+ extensionsForMessage = allowedExtensions.join(", ").toLowerCase();
+ r("{file}", this._options.formatFileName(name));
+ r("{extensions}", extensionsForMessage);
+ r("{sizeLimit}", this._formatSize(validationBase.sizeLimit));
+ r("{minSizeLimit}", this._formatSize(validationBase.minSizeLimit));
+ placeholderMatch = message.match(/(\{\w+\})/g);
+ if (placeholderMatch !== null) {
+ qq.each(placeholderMatch, function(idx, placeholder) {
+ r(placeholder, names[idx]);
+ });
+ }
+ this._options.callbacks.onError(null, name, message, undefined);
+ return message;
+ },
+ _manualRetry: function(id, callback) {
+ if (this._onBeforeManualRetry(id)) {
+ this._netUploadedOrQueued++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ if (callback) {
+ callback(id);
+ } else {
+ this._handler.retry(id);
+ }
+ return true;
+ }
+ },
+ _maybeAllComplete: function(id, status) {
+ var self = this, notFinished = this._getNotFinished();
+ if (status === qq.status.UPLOAD_SUCCESSFUL) {
+ this._succeededSinceLastAllComplete.push(id);
+ } else if (status === qq.status.UPLOAD_FAILED) {
+ this._failedSinceLastAllComplete.push(id);
+ }
+ if (notFinished === 0 && (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {
+ setTimeout(function() {
+ self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);
+ }, 0);
+ }
+ },
+ _maybeHandleIos8SafariWorkaround: function() {
+ var self = this;
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ setTimeout(function() {
+ window.alert(self._options.messages.unsupportedBrowserIos8Safari);
+ }, 0);
+ throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);
+ }
+ },
+ _maybeParseAndSendUploadError: function(id, name, response, xhr) {
+ if (!response.success) {
+ if (xhr && xhr.status !== 200 && !response.error) {
+ this._options.callbacks.onError(id, name, "XHR returned response code " + xhr.status, xhr);
+ } else {
+ var errorReason = response.error ? response.error : this._options.text.defaultResponseError;
+ this._options.callbacks.onError(id, name, errorReason, xhr);
+ }
+ }
+ },
+ _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {
+ var self = this;
+ if (items.length > index) {
+ if (validItem || !this._options.validation.stopOnFirstInvalidFile) {
+ setTimeout(function() {
+ var validationDescriptor = self._getValidationDescriptor(items[index]), buttonId = self._getButtonId(items[index].file), button = self._getButton(buttonId);
+ self._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),
+ onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),
+ onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),
+ identifier: "Item '" + validationDescriptor.name + "', size: " + validationDescriptor.size
+ });
+ }, 0);
+ } else if (!validItem) {
+ for (;index < items.length; index++) {
+ self._fileOrBlobRejected(items[index].id);
+ }
+ }
+ }
+ },
+ _onAllComplete: function(successful, failed) {
+ this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);
+ this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ },
+ _onAutoRetry: function(id, name, responseJSON, xhr, callback) {
+ var self = this;
+ self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];
+ if (self._shouldAutoRetry(id, name, responseJSON)) {
+ var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1e3;
+ self._maybeParseAndSendUploadError.apply(self, arguments);
+ self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);
+ self._onBeforeAutoRetry(id, name);
+ self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ self._retryTimeouts[id] = setTimeout(function() {
+ self.log("Starting retry for " + name + "...");
+ if (callback) {
+ callback(id);
+ } else {
+ self._handler.retry(id);
+ }
+ }, retryWaitPeriod);
+ return true;
+ }
+ },
+ _onBeforeAutoRetry: function(id, name) {
+ this.log("Waiting " + this._options.retry.autoAttemptDelay + " seconds before retrying " + name + "...");
+ },
+ _onBeforeManualRetry: function(id) {
+ var itemLimit = this._currentItemLimit, fileName;
+ if (this._preventRetries[id]) {
+ this.log("Retries are forbidden for id " + id, "warn");
+ return false;
+ } else if (this._handler.isValid(id)) {
+ fileName = this.getName(id);
+ if (this._options.callbacks.onManualRetry(id, fileName) === false) {
+ return false;
+ }
+ if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {
+ this._itemError("retryFailTooManyItems");
+ return false;
+ }
+ this.log("Retrying upload for '" + fileName + "' (id: " + id + ")...");
+ return true;
+ } else {
+ this.log("'" + id + "' is not a valid file ID", "error");
+ return false;
+ }
+ },
+ _onCancel: function(id, name) {
+ this._netUploadedOrQueued--;
+ clearTimeout(this._retryTimeouts[id]);
+ var storedItemIndex = qq.indexOf(this._storedIds, id);
+ if (!this._options.autoUpload && storedItemIndex >= 0) {
+ this._storedIds.splice(storedItemIndex, 1);
+ }
+ this._uploadData.setStatus(id, qq.status.CANCELED);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ if (!result.success) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);
+ if (result[this._options.retry.preventRetryResponseProperty] === true) {
+ this._preventRetries[id] = true;
+ }
+ } else {
+ if (result.thumbnailUrl) {
+ this._thumbnailUrls[id] = result.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);
+ }
+ this._maybeParseAndSendUploadError(id, name, result, xhr);
+ return result.success ? true : false;
+ },
+ _onDelete: function(id) {
+ this._uploadData.setStatus(id, qq.status.DELETING);
+ },
+ _onDeleteComplete: function(id, xhrOrXdr, isError) {
+ var name = this.getName(id);
+ if (isError) {
+ this._uploadData.setStatus(id, qq.status.DELETE_FAILED);
+ this.log("Delete request for '" + name + "' has failed.", "error");
+ if (xhrOrXdr.withCredentials === undefined) {
+ this._options.callbacks.onError(id, name, "Delete request failed", xhrOrXdr);
+ } else {
+ this._options.callbacks.onError(id, name, "Delete request failed with response code " + xhrOrXdr.status, xhrOrXdr);
+ }
+ } else {
+ this._netUploadedOrQueued--;
+ this._netUploaded--;
+ this._handler.expunge(id);
+ this._uploadData.setStatus(id, qq.status.DELETED);
+ this.log("Delete request for '" + name + "' has succeeded.");
+ }
+ },
+ _onInputChange: function(input) {
+ var fileIndex;
+ if (qq.supportedFeatures.ajaxUploading) {
+ for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {
+ this._annotateWithButtonId(input.files[fileIndex], input);
+ }
+ this.addFiles(input.files);
+ } else if (input.value.length > 0) {
+ this.addFiles(input);
+ }
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);
+ },
+ _onSubmit: function(id, name) {},
+ _onSubmitCallbackSuccess: function(id, name) {
+ this._onSubmit.apply(this, arguments);
+ this._uploadData.setStatus(id, qq.status.SUBMITTED);
+ this._onSubmitted.apply(this, arguments);
+ if (this._options.autoUpload) {
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ this._uploadFile(id);
+ } else {
+ this._storeForLater(id);
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ }
+ },
+ _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {
+ var uuid = this.getUuid(id), adjustedOnSuccessCallback;
+ if (onSuccessCallback) {
+ adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);
+ }
+ if (this._isDeletePossible()) {
+ this._handleCheckedCallback({
+ name: "onSubmitDelete",
+ callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),
+ onSuccess: adjustedOnSuccessCallback || qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),
+ identifier: id
+ });
+ return true;
+ } else {
+ this.log("Delete request ignored for ID " + id + ", delete feature is disabled or request not possible " + "due to CORS on a user agent that does not support pre-flighting.", "warn");
+ return false;
+ }
+ },
+ _onSubmitted: function(id) {},
+ _onTotalProgress: function(loaded, total) {
+ this._options.callbacks.onTotalProgress(loaded, total);
+ },
+ _onUploadPrep: function(id) {},
+ _onUpload: function(id, name) {
+ this._uploadData.setStatus(id, qq.status.UPLOADING);
+ },
+ _onUploadChunk: function(id, chunkData) {},
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.PAUSED) {
+ clearTimeout(this._retryTimeouts[id]);
+ }
+ },
+ _onValidateBatchCallbackFailure: function(fileWrappers) {
+ var self = this;
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ self._fileOrBlobRejected(fileWrapper.id);
+ });
+ },
+ _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {
+ var errorMessage, itemLimit = this._currentItemLimit, proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;
+ if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {
+ if (items.length > 0) {
+ this._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),
+ onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),
+ onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),
+ identifier: "Item '" + items[0].file.name + "', size: " + items[0].file.size
+ });
+ } else {
+ this._itemError("noFilesError");
+ }
+ } else {
+ this._onValidateBatchCallbackFailure(items);
+ errorMessage = this._options.messages.tooManyItemsError.replace(/\{netItems\}/g, proposedNetFilesUploadedOrQueued).replace(/\{itemLimit\}/g, itemLimit);
+ this._batchError(errorMessage);
+ }
+ },
+ _onValidateCallbackFailure: function(items, index, params, endpoint) {
+ var nextIndex = index + 1;
+ this._fileOrBlobRejected(items[index].id, items[index].file.name);
+ this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ },
+ _onValidateCallbackSuccess: function(items, index, params, endpoint) {
+ var self = this, nextIndex = index + 1, validationDescriptor = this._getValidationDescriptor(items[index]);
+ this._validateFileOrBlobData(items[index], validationDescriptor).then(function() {
+ self._upload(items[index].id, params, endpoint);
+ self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);
+ }, function() {
+ self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ });
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ if (items.length === 0) {
+ this._itemError("noFilesError");
+ return;
+ }
+ var validationDescriptors = this._getValidationDescriptors(items), buttonId = this._getButtonId(items[0].file), button = this._getButton(buttonId);
+ this._handleCheckedCallback({
+ name: "onValidateBatch",
+ callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),
+ onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),
+ onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),
+ identifier: "batch validation"
+ });
+ },
+ _preventLeaveInProgress: function() {
+ var self = this;
+ this._disposeSupport.attach(window, "beforeunload", function(e) {
+ if (self.getInProgress()) {
+ e = e || window.event;
+ e.returnValue = self._options.messages.onLeave;
+ return self._options.messages.onLeave;
+ }
+ });
+ },
+ _refreshSessionData: function() {
+ var self = this, options = this._options.session;
+ if (qq.Session && this._options.session.endpoint != null) {
+ if (!this._session) {
+ qq.extend(options, {
+ cors: this._options.cors
+ });
+ options.log = qq.bind(this.log, this);
+ options.addFileRecord = qq.bind(this._addCannedFile, this);
+ this._session = new qq.Session(options);
+ }
+ setTimeout(function() {
+ self._session.refresh().then(function(response, xhrOrXdr) {
+ self._sessionRequestComplete();
+ self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);
+ }, function(response, xhrOrXdr) {
+ self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);
+ });
+ }, 0);
+ }
+ },
+ _sessionRequestComplete: function() {},
+ _setSize: function(id, newSize) {
+ this._uploadData.updateSize(id, newSize);
+ this._totalProgress && this._totalProgress.onNewSize(id);
+ },
+ _shouldAutoRetry: function(id, name, responseJSON) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!this._preventRetries[id] && this._options.retry.enableAuto && uploadData.status !== qq.status.PAUSED) {
+ if (this._autoRetries[id] === undefined) {
+ this._autoRetries[id] = 0;
+ }
+ if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {
+ this._autoRetries[id] += 1;
+ return true;
+ }
+ }
+ return false;
+ },
+ _storeForLater: function(id) {
+ this._storedIds.push(id);
+ },
+ _trackButton: function(id) {
+ var buttonId;
+ if (qq.supportedFeatures.ajaxUploading) {
+ buttonId = this._handler.getFile(id).qqButtonId;
+ } else {
+ buttonId = this._getButtonId(this._handler.getInput(id));
+ }
+ if (buttonId) {
+ this._buttonIdsForFileIds[id] = buttonId;
+ }
+ },
+ _updateFormSupportAndParams: function(formElementOrId) {
+ this._options.form.element = formElementOrId;
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this.setEndpoint(this._formSupport.newEndpoint);
+ }
+ }
+ },
+ _upload: function(id, params, endpoint) {
+ var name = this.getName(id);
+ if (params) {
+ this.setParams(params, id);
+ }
+ if (endpoint) {
+ this.setEndpoint(endpoint, id);
+ }
+ this._handleCheckedCallback({
+ name: "onSubmit",
+ callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),
+ onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),
+ onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),
+ identifier: id
+ });
+ },
+ _uploadFile: function(id) {
+ if (!this._handler.upload(id)) {
+ this._uploadData.setStatus(id, qq.status.QUEUED);
+ }
+ },
+ _uploadStoredFiles: function() {
+ var idToUpload, stillSubmitting, self = this;
+ while (this._storedIds.length) {
+ idToUpload = this._storedIds.shift();
+ this._uploadFile(idToUpload);
+ }
+ stillSubmitting = this.getUploads({
+ status: qq.status.SUBMITTING
+ }).length;
+ if (stillSubmitting) {
+ qq.log("Still waiting for " + stillSubmitting + " files to clear submit queue. Will re-parse stored IDs array shortly.");
+ setTimeout(function() {
+ self._uploadStoredFiles();
+ }, 1e3);
+ }
+ },
+ _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {
+ var self = this, file = function() {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return fileWrapper.file.referenceBlob;
+ }
+ return fileWrapper.file;
+ }(), name = validationDescriptor.name, size = validationDescriptor.size, buttonId = this._getButtonId(fileWrapper.file), validationBase = this._getValidationBase(buttonId), validityChecker = new qq.Promise();
+ validityChecker.then(function() {}, function() {
+ self._fileOrBlobRejected(fileWrapper.id, name);
+ });
+ if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {
+ this._itemError("typeError", name, file);
+ return validityChecker.failure();
+ }
+ if (!this._options.validation.allowEmpty && size === 0) {
+ this._itemError("emptyError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {
+ this._itemError("sizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && size < validationBase.minSizeLimit) {
+ this._itemError("minSizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {
+ new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(validityChecker.success, function(errorCode) {
+ self._itemError(errorCode + "ImageError", name, file);
+ validityChecker.failure();
+ });
+ } else {
+ validityChecker.success();
+ }
+ return validityChecker;
+ },
+ _wrapCallbacks: function() {
+ var self, safeCallback, prop;
+ self = this;
+ safeCallback = function(name, callback, args) {
+ var errorMsg;
+ try {
+ return callback.apply(self, args);
+ } catch (exception) {
+ errorMsg = exception.message || exception.toString();
+ self.log("Caught exception in '" + name + "' callback - " + errorMsg, "error");
+ }
+ };
+ for (prop in this._options.callbacks) {
+ (function() {
+ var callbackName, callbackFunc;
+ callbackName = prop;
+ callbackFunc = self._options.callbacks[callbackName];
+ self._options.callbacks[callbackName] = function() {
+ return safeCallback(callbackName, callbackFunc, arguments);
+ };
+ })();
+ }
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.FineUploaderBasic = function(o) {
+ var self = this;
+ this._options = {
+ debug: false,
+ button: null,
+ multiple: true,
+ maxConnections: 3,
+ disableCancelForFormUploads: false,
+ autoUpload: true,
+ request: {
+ customHeaders: {},
+ endpoint: "/server/upload",
+ filenameParam: "qqfilename",
+ forceMultipart: true,
+ inputName: "qqfile",
+ method: "POST",
+ params: {},
+ paramsInBody: true,
+ totalFileSizeName: "qqtotalfilesize",
+ uuidName: "qquuid"
+ },
+ validation: {
+ allowedExtensions: [],
+ sizeLimit: 0,
+ minSizeLimit: 0,
+ itemLimit: 0,
+ stopOnFirstInvalidFile: true,
+ acceptFiles: null,
+ image: {
+ maxHeight: 0,
+ maxWidth: 0,
+ minHeight: 0,
+ minWidth: 0
+ },
+ allowEmpty: false
+ },
+ callbacks: {
+ onSubmit: function(id, name) {},
+ onSubmitted: function(id, name) {},
+ onComplete: function(id, name, responseJSON, maybeXhr) {},
+ onAllComplete: function(successful, failed) {},
+ onCancel: function(id, name) {},
+ onUpload: function(id, name) {},
+ onUploadChunk: function(id, name, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onProgress: function(id, name, loaded, total) {},
+ onTotalProgress: function(loaded, total) {},
+ onError: function(id, name, reason, maybeXhrOrXdr) {},
+ onAutoRetry: function(id, name, attemptNumber) {},
+ onManualRetry: function(id, name) {},
+ onValidateBatch: function(fileOrBlobData) {},
+ onValidate: function(fileOrBlobData) {},
+ onSubmitDelete: function(id) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {},
+ onPasteReceived: function(blob) {},
+ onStatusChange: function(id, oldStatus, newStatus) {},
+ onSessionRequestComplete: function(response, success, xhrOrXdr) {}
+ },
+ messages: {
+ typeError: "{file} has an invalid extension. Valid extension(s): {extensions}.",
+ sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
+ minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
+ emptyError: "{file} is empty, please select files again without it.",
+ noFilesError: "No files to upload.",
+ tooManyItemsError: "Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.",
+ maxHeightImageError: "Image is too tall.",
+ maxWidthImageError: "Image is too wide.",
+ minHeightImageError: "Image is not tall enough.",
+ minWidthImageError: "Image is not wide enough.",
+ retryFailTooManyItems: "Retry failed - you have reached your file limit.",
+ onLeave: "The files are being uploaded, if you leave now the upload will be canceled.",
+ unsupportedBrowserIos8Safari: "Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues."
+ },
+ retry: {
+ enableAuto: false,
+ maxAutoAttempts: 3,
+ autoAttemptDelay: 5,
+ preventRetryResponseProperty: "preventRetry"
+ },
+ classes: {
+ buttonHover: "qq-upload-button-hover",
+ buttonFocus: "qq-upload-button-focus"
+ },
+ chunking: {
+ enabled: false,
+ concurrent: {
+ enabled: false
+ },
+ mandatory: false,
+ paramNames: {
+ partIndex: "qqpartindex",
+ partByteOffset: "qqpartbyteoffset",
+ chunkSize: "qqchunksize",
+ totalFileSize: "qqtotalfilesize",
+ totalParts: "qqtotalparts"
+ },
+ partSize: 2e6,
+ success: {
+ endpoint: null
+ }
+ },
+ resume: {
+ enabled: false,
+ recordsExpireIn: 7,
+ paramNames: {
+ resuming: "qqresume"
+ }
+ },
+ formatFileName: function(fileOrBlobName) {
+ return fileOrBlobName;
+ },
+ text: {
+ defaultResponseError: "Upload failure reason unknown",
+ fileInputTitle: "file input",
+ sizeSymbols: [ "kB", "MB", "GB", "TB", "PB", "EB" ]
+ },
+ deleteFile: {
+ enabled: false,
+ method: "DELETE",
+ endpoint: "/server/upload",
+ customHeaders: {},
+ params: {}
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false,
+ allowXdr: false
+ },
+ blobs: {
+ defaultName: "misc_data"
+ },
+ paste: {
+ targetElement: null,
+ defaultName: "pasted_image"
+ },
+ camera: {
+ ios: false,
+ button: null
+ },
+ extraButtons: [],
+ session: {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ refreshOnReset: true
+ },
+ form: {
+ element: "qq-form",
+ autoUpload: false,
+ interceptSubmit: true
+ },
+ scaling: {
+ customResizer: null,
+ sendOriginal: true,
+ orient: true,
+ defaultType: null,
+ defaultQuality: 80,
+ failureText: "Failed to scale",
+ includeExif: false,
+ sizes: []
+ },
+ workarounds: {
+ iosEmptyVideos: true,
+ ios8SafariUploads: true,
+ ios8BrowserCrash: false
+ }
+ };
+ qq.extend(this._options, o, true);
+ this._buttons = [];
+ this._extraButtonSpecs = {};
+ this._buttonIdsForFileIds = [];
+ this._wrapCallbacks();
+ this._disposeSupport = new qq.DisposeSupport();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData = this._createUploadDataTracker();
+ this._initFormSupportAndParams();
+ this._customHeadersStore = this._createStore(this._options.request.customHeaders);
+ this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);
+ this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);
+ this._endpointStore = this._createStore(this._options.request.endpoint);
+ this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);
+ this._handler = this._createUploadHandler();
+ this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();
+ if (this._options.button) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._options.button,
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._generateExtraButtonSpecs();
+ this._handleCameraAccess();
+ if (this._options.paste.targetElement) {
+ if (qq.PasteSupport) {
+ this._pasteHandler = this._createPasteHandler();
+ } else {
+ this.log("Paste support module not found", "error");
+ }
+ }
+ this._preventLeaveInProgress();
+ this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));
+ this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._scaler = qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this)) || {};
+ if (this._scaler.enabled) {
+ this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);
+ }
+ if (qq.TotalProgress && qq.supportedFeatures.progressBar) {
+ this._totalProgress = new qq.TotalProgress(qq.bind(this._onTotalProgress, this), function(id) {
+ var entry = self._uploadData.retrieve({
+ id: id
+ });
+ return entry && entry.size || 0;
+ });
+ }
+ this._currentItemLimit = this._options.validation.itemLimit;
+ };
+ qq.FineUploaderBasic.prototype = qq.basePublicApi;
+ qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);
+ })();
+ qq.AjaxRequester = function(o) {
+ "use strict";
+ var log, shouldParamsBeInQueryString, queue = [], requestData = {}, options = {
+ acceptHeader: null,
+ validMethods: [ "PATCH", "POST", "PUT" ],
+ method: "POST",
+ contentType: "application/x-www-form-urlencoded",
+ maxConnections: 3,
+ customHeaders: {},
+ endpointStore: {},
+ paramsStore: {},
+ mandatedParams: {},
+ allowXRequestedWithAndCacheControl: true,
+ successfulResponseCodes: {
+ DELETE: [ 200, 202, 204 ],
+ PATCH: [ 200, 201, 202, 203, 204 ],
+ POST: [ 200, 201, 202, 203, 204 ],
+ PUT: [ 200, 201, 202, 203, 204 ],
+ GET: [ 200 ]
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onSend: function(id) {},
+ onComplete: function(id, xhrOrXdr, isError) {},
+ onProgress: null
+ };
+ qq.extend(options, o);
+ log = options.log;
+ if (qq.indexOf(options.validMethods, options.method) < 0) {
+ throw new Error("'" + options.method + "' is not a supported method for this type of request!");
+ }
+ function isSimpleMethod() {
+ return qq.indexOf([ "GET", "POST", "HEAD" ], options.method) >= 0;
+ }
+ function containsNonSimpleHeaders(headers) {
+ var containsNonSimple = false;
+ qq.each(containsNonSimple, function(idx, header) {
+ if (qq.indexOf([ "Accept", "Accept-Language", "Content-Language", "Content-Type" ], header) < 0) {
+ containsNonSimple = true;
+ return false;
+ }
+ });
+ return containsNonSimple;
+ }
+ function isXdr(xhr) {
+ return options.cors.expected && xhr.withCredentials === undefined;
+ }
+ function getCorsAjaxTransport() {
+ var xhrOrXdr;
+ if (window.XMLHttpRequest || window.ActiveXObject) {
+ xhrOrXdr = qq.createXhrInstance();
+ if (xhrOrXdr.withCredentials === undefined) {
+ xhrOrXdr = new XDomainRequest();
+ xhrOrXdr.onload = function() {};
+ xhrOrXdr.onerror = function() {};
+ xhrOrXdr.ontimeout = function() {};
+ xhrOrXdr.onprogress = function() {};
+ }
+ }
+ return xhrOrXdr;
+ }
+ function getXhrOrXdr(id, suppliedXhr) {
+ var xhrOrXdr = requestData[id].xhr;
+ if (!xhrOrXdr) {
+ if (suppliedXhr) {
+ xhrOrXdr = suppliedXhr;
+ } else {
+ if (options.cors.expected) {
+ xhrOrXdr = getCorsAjaxTransport();
+ } else {
+ xhrOrXdr = qq.createXhrInstance();
+ }
+ }
+ requestData[id].xhr = xhrOrXdr;
+ }
+ return xhrOrXdr;
+ }
+ function dequeue(id) {
+ var i = qq.indexOf(queue, id), max = options.maxConnections, nextId;
+ delete requestData[id];
+ queue.splice(i, 1);
+ if (queue.length >= max && i < max) {
+ nextId = queue[max - 1];
+ sendRequest(nextId);
+ }
+ }
+ function onComplete(id, xdrError) {
+ var xhr = getXhrOrXdr(id), method = options.method, isError = xdrError === true;
+ dequeue(id);
+ if (isError) {
+ log(method + " request for " + id + " has failed", "error");
+ } else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {
+ isError = true;
+ log(method + " request for " + id + " has failed - response code " + xhr.status, "error");
+ }
+ options.onComplete(id, xhr, isError);
+ }
+ function getParams(id) {
+ var onDemandParams = requestData[id].additionalParams, mandatedParams = options.mandatedParams, params;
+ if (options.paramsStore.get) {
+ params = options.paramsStore.get(id);
+ }
+ if (onDemandParams) {
+ qq.each(onDemandParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ if (mandatedParams) {
+ qq.each(mandatedParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ return params;
+ }
+ function sendRequest(id, optXhr) {
+ var xhr = getXhrOrXdr(id, optXhr), method = options.method, params = getParams(id), payload = requestData[id].payload, url;
+ options.onSend(id);
+ url = createUrl(id, params, requestData[id].additionalQueryParams);
+ if (isXdr(xhr)) {
+ xhr.onload = getXdrLoadHandler(id);
+ xhr.onerror = getXdrErrorHandler(id);
+ } else {
+ xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);
+ }
+ registerForUploadProgress(id);
+ xhr.open(method, url, true);
+ if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {
+ xhr.withCredentials = true;
+ }
+ setHeaders(id);
+ log("Sending " + method + " request for " + id);
+ if (payload) {
+ xhr.send(payload);
+ } else if (shouldParamsBeInQueryString || !params) {
+ xhr.send();
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/x-www-form-urlencoded") >= 0) {
+ xhr.send(qq.obj2url(params, ""));
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/json") >= 0) {
+ xhr.send(JSON.stringify(params));
+ } else {
+ xhr.send(params);
+ }
+ return xhr;
+ }
+ function createUrl(id, params, additionalQueryParams) {
+ var endpoint = options.endpointStore.get(id), addToPath = requestData[id].addToPath;
+ if (addToPath != undefined) {
+ endpoint += "/" + addToPath;
+ }
+ if (shouldParamsBeInQueryString && params) {
+ endpoint = qq.obj2url(params, endpoint);
+ }
+ if (additionalQueryParams) {
+ endpoint = qq.obj2url(additionalQueryParams, endpoint);
+ }
+ return endpoint;
+ }
+ function getXhrReadyStateChangeHandler(id) {
+ return function() {
+ if (getXhrOrXdr(id).readyState === 4) {
+ onComplete(id);
+ }
+ };
+ }
+ function registerForUploadProgress(id) {
+ var onProgress = options.onProgress;
+ if (onProgress) {
+ getXhrOrXdr(id).upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ onProgress(id, e.loaded, e.total);
+ }
+ };
+ }
+ }
+ function getXdrLoadHandler(id) {
+ return function() {
+ onComplete(id);
+ };
+ }
+ function getXdrErrorHandler(id) {
+ return function() {
+ onComplete(id, true);
+ };
+ }
+ function setHeaders(id) {
+ var xhr = getXhrOrXdr(id), customHeaders = options.customHeaders, onDemandHeaders = requestData[id].additionalHeaders || {}, method = options.method, allHeaders = {};
+ if (!isXdr(xhr)) {
+ options.acceptHeader && xhr.setRequestHeader("Accept", options.acceptHeader);
+ if (options.allowXRequestedWithAndCacheControl) {
+ if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ xhr.setRequestHeader("Cache-Control", "no-cache");
+ }
+ }
+ if (options.contentType && (method === "POST" || method === "PUT")) {
+ xhr.setRequestHeader("Content-Type", options.contentType);
+ }
+ qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);
+ qq.extend(allHeaders, onDemandHeaders);
+ qq.each(allHeaders, function(name, val) {
+ xhr.setRequestHeader(name, val);
+ });
+ }
+ }
+ function isResponseSuccessful(responseCode) {
+ return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;
+ }
+ function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {
+ requestData[id] = {
+ addToPath: addToPath,
+ additionalParams: additionalParams,
+ additionalQueryParams: additionalQueryParams,
+ additionalHeaders: additionalHeaders,
+ payload: payload
+ };
+ var len = queue.push(id);
+ if (len <= options.maxConnections) {
+ return sendRequest(id, optXhr);
+ }
+ }
+ shouldParamsBeInQueryString = options.method === "GET" || options.method === "DELETE";
+ qq.extend(this, {
+ initTransport: function(id) {
+ var path, params, headers, payload, cacheBuster, additionalQueryParams;
+ return {
+ withPath: function(appendToPath) {
+ path = appendToPath;
+ return this;
+ },
+ withParams: function(additionalParams) {
+ params = additionalParams;
+ return this;
+ },
+ withQueryParams: function(_additionalQueryParams_) {
+ additionalQueryParams = _additionalQueryParams_;
+ return this;
+ },
+ withHeaders: function(additionalHeaders) {
+ headers = additionalHeaders;
+ return this;
+ },
+ withPayload: function(thePayload) {
+ payload = thePayload;
+ return this;
+ },
+ withCacheBuster: function() {
+ cacheBuster = true;
+ return this;
+ },
+ send: function(optXhr) {
+ if (cacheBuster && qq.indexOf([ "GET", "DELETE" ], options.method) >= 0) {
+ params.qqtimestamp = new Date().getTime();
+ }
+ return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);
+ }
+ };
+ },
+ canceled: function(id) {
+ dequeue(id);
+ }
+ });
+ };
+ qq.UploadHandler = function(spec) {
+ "use strict";
+ var proxy = spec.proxy, fileState = {}, onCancel = proxy.onCancel, getName = proxy.getName;
+ qq.extend(this, {
+ add: function(id, fileItem) {
+ fileState[id] = fileItem;
+ fileState[id].temp = {};
+ },
+ cancel: function(id) {
+ var self = this, cancelFinalizationEffort = new qq.Promise(), onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);
+ onCancelRetVal.then(function() {
+ if (self.isValid(id)) {
+ fileState[id].canceled = true;
+ self.expunge(id);
+ }
+ cancelFinalizationEffort.success();
+ });
+ },
+ expunge: function(id) {
+ delete fileState[id];
+ },
+ getThirdPartyFileId: function(id) {
+ return fileState[id].key;
+ },
+ isValid: function(id) {
+ return fileState[id] !== undefined;
+ },
+ reset: function() {
+ fileState = {};
+ },
+ _getFileState: function(id) {
+ return fileState[id];
+ },
+ _setThirdPartyFileId: function(id, thirdPartyFileId) {
+ fileState[id].key = thirdPartyFileId;
+ },
+ _wasCanceled: function(id) {
+ return !!fileState[id].canceled;
+ }
+ });
+ };
+ qq.UploadHandlerController = function(o, namespace) {
+ "use strict";
+ var controller = this, chunkingPossible = false, concurrentChunkingPossible = false, chunking, preventRetryResponse, log, handler, options = {
+ paramsStore: {},
+ maxConnections: 3,
+ chunking: {
+ enabled: false,
+ multiple: {
+ enabled: false
+ }
+ },
+ log: function(str, level) {},
+ onProgress: function(id, fileName, loaded, total) {},
+ onComplete: function(id, fileName, response, xhr) {},
+ onCancel: function(id, fileName) {},
+ onUploadPrep: function(id) {},
+ onUpload: function(id, fileName) {},
+ onUploadChunk: function(id, fileName, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, response, xhr) {},
+ onAutoRetry: function(id, fileName, response, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onUuidChanged: function(id, newUuid) {},
+ getName: function(id) {},
+ setSize: function(id, newSize) {},
+ isQueued: function(id) {},
+ getIdsInProxyGroup: function(id) {},
+ getIdsInBatch: function(id) {}
+ }, chunked = {
+ done: function(id, chunkIdx, response, xhr) {
+ var chunkData = handler._getChunkData(id, chunkIdx);
+ handler._getFileState(id).attemptingResume = false;
+ delete handler._getFileState(id).temp.chunkProgress[chunkIdx];
+ handler._getFileState(id).loaded += chunkData.size;
+ options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);
+ },
+ finalize: function(id) {
+ var size = options.getSize(id), name = options.getName(id);
+ log("All chunks have been uploaded for " + id + " - finalizing....");
+ handler.finalizeChunks(id).then(function(response, xhr) {
+ log("Finalize successful for " + id);
+ var normaizedResponse = upload.normalizeResponse(response, true);
+ options.onProgress(id, name, size, size);
+ handler._maybeDeletePersistedChunkData(id);
+ upload.cleanup(id, normaizedResponse, xhr);
+ }, function(response, xhr) {
+ var normaizedResponse = upload.normalizeResponse(response, false);
+ log("Problem finalizing chunks for file ID " + id + " - " + normaizedResponse.error, "error");
+ if (normaizedResponse.reset) {
+ chunked.reset(id);
+ }
+ if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {
+ upload.cleanup(id, normaizedResponse, xhr);
+ }
+ });
+ },
+ handleFailure: function(chunkIdx, id, response, xhr) {
+ var name = options.getName(id);
+ log("Chunked upload request failed for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var responseToReport = upload.normalizeResponse(response, false), inProgressIdx;
+ if (responseToReport.reset) {
+ chunked.reset(id);
+ } else {
+ inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);
+ if (inProgressIdx >= 0) {
+ handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);
+ handler._getFileState(id).chunking.remaining.unshift(chunkIdx);
+ }
+ }
+ if (!handler._getFileState(id).temp.ignoreFailure) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = true;
+ log(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));
+ qq.each(handler._getXhrs(id), function(ckid, ckXhr) {
+ log(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ", id, ckid, ckXhr.readyState));
+ ckXhr.abort();
+ ckXhr._cancelled = true;
+ });
+ handler.moveInProgressToRemaining(id);
+ connectionManager.free(id, true);
+ }
+ if (!options.onAutoRetry(id, name, responseToReport, xhr)) {
+ upload.cleanup(id, responseToReport, xhr);
+ }
+ }
+ },
+ hasMoreParts: function(id) {
+ return !!handler._getFileState(id).chunking.remaining.length;
+ },
+ nextPart: function(id) {
+ var nextIdx = handler._getFileState(id).chunking.remaining.shift();
+ if (nextIdx >= handler._getTotalChunks(id)) {
+ nextIdx = null;
+ }
+ return nextIdx;
+ },
+ reset: function(id) {
+ log("Server or callback has ordered chunking effort to be restarted on next attempt for item ID " + id, "error");
+ handler._maybeDeletePersistedChunkData(id);
+ handler.reevaluateChunking(id);
+ handler._getFileState(id).loaded = 0;
+ },
+ sendNext: function(id) {
+ var size = options.getSize(id), name = options.getName(id), chunkIdx = chunked.nextPart(id), chunkData = handler._getChunkData(id, chunkIdx), resuming = handler._getFileState(id).attemptingResume, inProgressChunks = handler._getFileState(id).chunking.inProgress || [];
+ if (handler._getFileState(id).loaded == null) {
+ handler._getFileState(id).loaded = 0;
+ }
+ if (resuming && options.onResume(id, name, chunkData) === false) {
+ chunked.reset(id);
+ chunkIdx = chunked.nextPart(id);
+ chunkData = handler._getChunkData(id, chunkIdx);
+ resuming = false;
+ }
+ if (chunkIdx == null && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else {
+ log(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.", id, chunkIdx, chunkData.start + 1, chunkData.end, size));
+ options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));
+ inProgressChunks.push(chunkIdx);
+ handler._getFileState(id).chunking.inProgress = inProgressChunks;
+ if (concurrentChunkingPossible) {
+ connectionManager.open(id, chunkIdx);
+ }
+ if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {
+ chunked.sendNext(id);
+ }
+ if (chunkData.blob.size === 0) {
+ log(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.", chunkIdx, id), "error");
+ chunked.handleFailure(chunkIdx, id, "File is no longer available", null);
+ } else {
+ handler.uploadChunk(id, chunkIdx, resuming).then(function success(response, xhr) {
+ log("Chunked upload request succeeded for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var inProgressChunks = handler._getFileState(id).chunking.inProgress || [], responseToReport = upload.normalizeResponse(response, true), inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);
+ log(qq.format("Chunk {} for file {} uploaded successfully.", chunkIdx, id));
+ chunked.done(id, chunkIdx, responseToReport, xhr);
+ if (inProgressChunkIdx >= 0) {
+ inProgressChunks.splice(inProgressChunkIdx, 1);
+ }
+ handler._maybePersistChunkedState(id);
+ if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else if (chunked.hasMoreParts(id)) {
+ chunked.sendNext(id);
+ } else {
+ log(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}", id, JSON.stringify(inProgressChunks)));
+ }
+ }, function failure(response, xhr) {
+ chunked.handleFailure(chunkIdx, id, response, xhr);
+ }).done(function() {
+ handler.clearXhr(id, chunkIdx);
+ });
+ }
+ }
+ }
+ }, connectionManager = {
+ _open: [],
+ _openChunks: {},
+ _waiting: [],
+ available: function() {
+ var max = options.maxConnections, openChunkEntriesCount = 0, openChunksCount = 0;
+ qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {
+ openChunkEntriesCount++;
+ openChunksCount += openChunkIndexes.length;
+ });
+ return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);
+ },
+ free: function(id, dontAllowNext) {
+ var allowNext = !dontAllowNext, waitingIndex = qq.indexOf(connectionManager._waiting, id), connectionsIndex = qq.indexOf(connectionManager._open, id), nextId;
+ delete connectionManager._openChunks[id];
+ if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {
+ log("Generated blob upload has ended for " + id + ", disposing generated blob.");
+ delete handler._getFileState(id).file;
+ }
+ if (waitingIndex >= 0) {
+ connectionManager._waiting.splice(waitingIndex, 1);
+ } else if (allowNext && connectionsIndex >= 0) {
+ connectionManager._open.splice(connectionsIndex, 1);
+ nextId = connectionManager._waiting.shift();
+ if (nextId >= 0) {
+ connectionManager._open.push(nextId);
+ upload.start(nextId);
+ }
+ }
+ },
+ getWaitingOrConnected: function() {
+ var waitingOrConnected = [];
+ qq.each(connectionManager._openChunks, function(fileId, chunks) {
+ if (chunks && chunks.length) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ qq.each(connectionManager._open, function(idx, fileId) {
+ if (!connectionManager._openChunks[fileId]) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);
+ return waitingOrConnected;
+ },
+ isUsingConnection: function(id) {
+ return qq.indexOf(connectionManager._open, id) >= 0;
+ },
+ open: function(id, chunkIdx) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.push(id);
+ }
+ if (connectionManager.available()) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.pop();
+ connectionManager._open.push(id);
+ } else {
+ (function() {
+ var openChunksEntry = connectionManager._openChunks[id] || [];
+ openChunksEntry.push(chunkIdx);
+ connectionManager._openChunks[id] = openChunksEntry;
+ })();
+ }
+ return true;
+ }
+ return false;
+ },
+ reset: function() {
+ connectionManager._waiting = [];
+ connectionManager._open = [];
+ }
+ }, simple = {
+ send: function(id, name) {
+ handler._getFileState(id).loaded = 0;
+ log("Sending simple upload request for " + id);
+ handler.uploadFile(id).then(function(response, optXhr) {
+ log("Simple upload request succeeded for " + id);
+ var responseToReport = upload.normalizeResponse(response, true), size = options.getSize(id);
+ options.onProgress(id, name, size, size);
+ upload.maybeNewUuid(id, responseToReport);
+ upload.cleanup(id, responseToReport, optXhr);
+ }, function(response, optXhr) {
+ log("Simple upload request failed for " + id);
+ var responseToReport = upload.normalizeResponse(response, false);
+ if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {
+ upload.cleanup(id, responseToReport, optXhr);
+ }
+ });
+ }
+ }, upload = {
+ cancel: function(id) {
+ log("Cancelling " + id);
+ options.paramsStore.remove(id);
+ connectionManager.free(id);
+ },
+ cleanup: function(id, response, optXhr) {
+ var name = options.getName(id);
+ options.onComplete(id, name, response, optXhr);
+ if (handler._getFileState(id)) {
+ handler._clearXhrs && handler._clearXhrs(id);
+ }
+ connectionManager.free(id);
+ },
+ getProxyOrBlob: function(id) {
+ return handler.getProxy && handler.getProxy(id) || handler.getFile && handler.getFile(id);
+ },
+ initHandler: function() {
+ var handlerType = namespace ? qq[namespace] : qq.traditional, handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? "Xhr" : "Form";
+ handler = new handlerType[handlerModuleSubtype + "UploadHandler"](options, {
+ getDataByUuid: options.getDataByUuid,
+ getName: options.getName,
+ getSize: options.getSize,
+ getUuid: options.getUuid,
+ log: log,
+ onCancel: options.onCancel,
+ onProgress: options.onProgress,
+ onUuidChanged: options.onUuidChanged
+ });
+ if (handler._removeExpiredChunkingRecords) {
+ handler._removeExpiredChunkingRecords();
+ }
+ },
+ isDeferredEligibleForUpload: function(id) {
+ return options.isQueued(id);
+ },
+ maybeDefer: function(id, blob) {
+ if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {
+ options.onUploadPrep(id);
+ log("Attempting to generate a blob on-demand for " + id);
+ blob.create().then(function(generatedBlob) {
+ log("Generated an on-demand blob for " + id);
+ handler.updateBlob(id, generatedBlob);
+ options.setSize(id, generatedBlob.size);
+ handler.reevaluateChunking(id);
+ upload.maybeSendDeferredFiles(id);
+ }, function(errorMessage) {
+ var errorResponse = {};
+ if (errorMessage) {
+ errorResponse.error = errorMessage;
+ }
+ log(qq.format("Failed to generate blob for ID {}. Error message: {}.", id, errorMessage), "error");
+ options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);
+ upload.maybeSendDeferredFiles(id);
+ connectionManager.free(id);
+ });
+ } else {
+ return upload.maybeSendDeferredFiles(id);
+ }
+ return false;
+ },
+ maybeSendDeferredFiles: function(id) {
+ var idsInGroup = options.getIdsInProxyGroup(id), uploadedThisId = false;
+ if (idsInGroup && idsInGroup.length) {
+ log("Maybe ready to upload proxy group file " + id);
+ qq.each(idsInGroup, function(idx, idInGroup) {
+ if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {
+ uploadedThisId = idInGroup === id;
+ upload.now(idInGroup);
+ } else if (upload.isDeferredEligibleForUpload(idInGroup)) {
+ return false;
+ }
+ });
+ } else {
+ uploadedThisId = true;
+ upload.now(id);
+ }
+ return uploadedThisId;
+ },
+ maybeNewUuid: function(id, response) {
+ if (response.newUuid !== undefined) {
+ options.onUuidChanged(id, response.newUuid);
+ }
+ },
+ normalizeResponse: function(originalResponse, successful) {
+ var response = originalResponse;
+ if (!qq.isObject(originalResponse)) {
+ response = {};
+ if (qq.isString(originalResponse) && !successful) {
+ response.error = originalResponse;
+ }
+ }
+ response.success = successful;
+ return response;
+ },
+ now: function(id) {
+ var name = options.getName(id);
+ if (!controller.isValid(id)) {
+ throw new qq.Error(id + " is not a valid file ID to upload!");
+ }
+ options.onUpload(id, name);
+ if (chunkingPossible && handler._shouldChunkThisFile(id)) {
+ chunked.sendNext(id);
+ } else {
+ simple.send(id, name);
+ }
+ },
+ start: function(id) {
+ var blobToUpload = upload.getProxyOrBlob(id);
+ if (blobToUpload) {
+ return upload.maybeDefer(id, blobToUpload);
+ } else {
+ upload.now(id);
+ return true;
+ }
+ }
+ };
+ qq.extend(this, {
+ add: function(id, file) {
+ handler.add.apply(this, arguments);
+ },
+ upload: function(id) {
+ if (connectionManager.open(id)) {
+ return upload.start(id);
+ }
+ return false;
+ },
+ retry: function(id) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = false;
+ }
+ if (connectionManager.isUsingConnection(id)) {
+ return upload.start(id);
+ } else {
+ return controller.upload(id);
+ }
+ },
+ cancel: function(id) {
+ var cancelRetVal = handler.cancel(id);
+ if (qq.isGenericPromise(cancelRetVal)) {
+ cancelRetVal.then(function() {
+ upload.cancel(id);
+ });
+ } else if (cancelRetVal !== false) {
+ upload.cancel(id);
+ }
+ },
+ cancelAll: function() {
+ var waitingOrConnected = connectionManager.getWaitingOrConnected(), i;
+ if (waitingOrConnected.length) {
+ for (i = waitingOrConnected.length - 1; i >= 0; i--) {
+ controller.cancel(waitingOrConnected[i]);
+ }
+ }
+ connectionManager.reset();
+ },
+ getFile: function(id) {
+ if (handler.getProxy && handler.getProxy(id)) {
+ return handler.getProxy(id).referenceBlob;
+ }
+ return handler.getFile && handler.getFile(id);
+ },
+ isProxied: function(id) {
+ return !!(handler.getProxy && handler.getProxy(id));
+ },
+ getInput: function(id) {
+ if (handler.getInput) {
+ return handler.getInput(id);
+ }
+ },
+ reset: function() {
+ log("Resetting upload handler");
+ controller.cancelAll();
+ connectionManager.reset();
+ handler.reset();
+ },
+ expunge: function(id) {
+ if (controller.isValid(id)) {
+ return handler.expunge(id);
+ }
+ },
+ isValid: function(id) {
+ return handler.isValid(id);
+ },
+ getResumableFilesData: function() {
+ if (handler.getResumableFilesData) {
+ return handler.getResumableFilesData();
+ }
+ return [];
+ },
+ getThirdPartyFileId: function(id) {
+ if (controller.isValid(id)) {
+ return handler.getThirdPartyFileId(id);
+ }
+ },
+ pause: function(id) {
+ if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {
+ connectionManager.free(id);
+ handler.moveInProgressToRemaining(id);
+ return true;
+ }
+ return false;
+ },
+ isResumable: function(id) {
+ return !!handler.isResumable && handler.isResumable(id);
+ }
+ });
+ qq.extend(options, o);
+ log = options.log;
+ chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;
+ concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;
+ preventRetryResponse = function() {
+ var response = {};
+ response[options.preventRetryParam] = true;
+ return response;
+ }();
+ upload.initHandler();
+ };
+ qq.WindowReceiveMessage = function(o) {
+ "use strict";
+ var options = {
+ log: function(message, level) {}
+ }, callbackWrapperDetachers = {};
+ qq.extend(options, o);
+ qq.extend(this, {
+ receiveMessage: function(id, callback) {
+ var onMessageCallbackWrapper = function(event) {
+ callback(event.data);
+ };
+ if (window.postMessage) {
+ callbackWrapperDetachers[id] = qq(window).attach("message", onMessageCallbackWrapper);
+ } else {
+ log("iframe message passing not supported in this browser!", "error");
+ }
+ },
+ stopReceivingMessages: function(id) {
+ if (window.postMessage) {
+ var detacher = callbackWrapperDetachers[id];
+ if (detacher) {
+ detacher();
+ }
+ }
+ }
+ });
+ };
+ qq.FormUploadHandler = function(spec) {
+ "use strict";
+ var options = spec.options, handler = this, proxy = spec.proxy, formHandlerInstanceId = qq.getUniqueId(), onloadCallbacks = {}, detachLoadEvents = {}, postMessageCallbackTimers = {}, isCors = options.isCors, inputName = options.inputName, getUuid = proxy.getUuid, log = proxy.log, corsMessageReceiver = new qq.WindowReceiveMessage({
+ log: log
+ });
+ function expungeFile(id) {
+ delete detachLoadEvents[id];
+ if (isCors) {
+ clearTimeout(postMessageCallbackTimers[id]);
+ delete postMessageCallbackTimers[id];
+ corsMessageReceiver.stopReceivingMessages(id);
+ }
+ var iframe = document.getElementById(handler._getIframeName(id));
+ if (iframe) {
+ iframe.setAttribute("src", "javascript:false;");
+ qq(iframe).remove();
+ }
+ }
+ function getFileIdForIframeName(iframeName) {
+ return iframeName.split("_")[0];
+ }
+ function initIframeForUpload(name) {
+ var iframe = qq.toElement("");
+ iframe.setAttribute("id", name);
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+ return iframe;
+ }
+ function registerPostMessageCallback(iframe, callback) {
+ var iframeName = iframe.id, fileId = getFileIdForIframeName(iframeName), uuid = getUuid(fileId);
+ onloadCallbacks[uuid] = callback;
+ detachLoadEvents[fileId] = qq(iframe).attach("load", function() {
+ if (handler.getInput(fileId)) {
+ log("Received iframe load event for CORS upload request (iframe name " + iframeName + ")");
+ postMessageCallbackTimers[iframeName] = setTimeout(function() {
+ var errorMessage = "No valid message received from loaded iframe for iframe name " + iframeName;
+ log(errorMessage, "error");
+ callback({
+ error: errorMessage
+ });
+ }, 1e3);
+ }
+ });
+ corsMessageReceiver.receiveMessage(iframeName, function(message) {
+ log("Received the following window message: '" + message + "'");
+ var fileId = getFileIdForIframeName(iframeName), response = handler._parseJsonResponse(message), uuid = response.uuid, onloadCallback;
+ if (uuid && onloadCallbacks[uuid]) {
+ log("Handling response for iframe name " + iframeName);
+ clearTimeout(postMessageCallbackTimers[iframeName]);
+ delete postMessageCallbackTimers[iframeName];
+ handler._detachLoadEvent(iframeName);
+ onloadCallback = onloadCallbacks[uuid];
+ delete onloadCallbacks[uuid];
+ corsMessageReceiver.stopReceivingMessages(iframeName);
+ onloadCallback(response);
+ } else if (!uuid) {
+ log("'" + message + "' does not contain a UUID - ignoring.");
+ }
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, fileInput) {
+ super_.add(id, {
+ input: fileInput
+ });
+ fileInput.setAttribute("name", inputName);
+ if (fileInput.parentNode) {
+ qq(fileInput).remove();
+ }
+ },
+ expunge: function(id) {
+ expungeFile(id);
+ super_.expunge(id);
+ },
+ isValid: function(id) {
+ return super_.isValid(id) && handler._getFileState(id).input !== undefined;
+ }
+ };
+ });
+ qq.extend(this, {
+ getInput: function(id) {
+ return handler._getFileState(id).input;
+ },
+ _attachLoadEvent: function(iframe, callback) {
+ var responseDescriptor;
+ if (isCors) {
+ registerPostMessageCallback(iframe, callback);
+ } else {
+ detachLoadEvents[iframe.id] = qq(iframe).attach("load", function() {
+ log("Received response for " + iframe.id);
+ if (!iframe.parentNode) {
+ return;
+ }
+ try {
+ if (iframe.contentDocument && iframe.contentDocument.body && iframe.contentDocument.body.innerHTML == "false") {
+ return;
+ }
+ } catch (error) {
+ log("Error when attempting to access iframe during handling of upload response (" + error.message + ")", "error");
+ responseDescriptor = {
+ success: false
+ };
+ }
+ callback(responseDescriptor);
+ });
+ }
+ },
+ _createIframe: function(id) {
+ var iframeName = handler._getIframeName(id);
+ return initIframeForUpload(iframeName);
+ },
+ _detachLoadEvent: function(id) {
+ if (detachLoadEvents[id] !== undefined) {
+ detachLoadEvents[id]();
+ delete detachLoadEvents[id];
+ }
+ },
+ _getIframeName: function(fileId) {
+ return fileId + "_" + formHandlerInstanceId;
+ },
+ _initFormForUpload: function(spec) {
+ var method = spec.method, endpoint = spec.endpoint, params = spec.params, paramsInBody = spec.paramsInBody, targetName = spec.targetName, form = qq.toElement(""), url = endpoint;
+ if (paramsInBody) {
+ qq.obj2Inputs(params, form);
+ } else {
+ url = qq.obj2url(params, endpoint);
+ }
+ form.setAttribute("action", url);
+ form.setAttribute("target", targetName);
+ form.style.display = "none";
+ document.body.appendChild(form);
+ return form;
+ },
+ _parseJsonResponse: function(innerHtmlOrMessage) {
+ var response = {};
+ try {
+ response = qq.parseJson(innerHtmlOrMessage);
+ } catch (error) {
+ log("Error when attempting to parse iframe upload response (" + error.message + ")", "error");
+ }
+ return response;
+ }
+ });
+ };
+ qq.XhrUploadHandler = function(spec) {
+ "use strict";
+ var handler = this, namespace = spec.options.namespace, proxy = spec.proxy, chunking = spec.options.chunking, resume = spec.options.resume, chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking, resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume, getName = proxy.getName, getSize = proxy.getSize, getUuid = proxy.getUuid, getEndpoint = proxy.getEndpoint, getDataByUuid = proxy.getDataByUuid, onUuidChanged = proxy.onUuidChanged, onProgress = proxy.onProgress, log = proxy.log;
+ function abort(id) {
+ qq.each(handler._getXhrs(id), function(xhrId, xhr) {
+ var ajaxRequester = handler._getAjaxRequester(id, xhrId);
+ xhr.onreadystatechange = null;
+ xhr.upload.onprogress = null;
+ xhr.abort();
+ ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, blobOrProxy) {
+ if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {
+ super_.add(id, {
+ file: blobOrProxy
+ });
+ } else if (blobOrProxy instanceof qq.BlobProxy) {
+ super_.add(id, {
+ proxy: blobOrProxy
+ });
+ } else {
+ throw new Error("Passed obj is not a File, Blob, or proxy");
+ }
+ handler._initTempState(id);
+ resumeEnabled && handler._maybePrepareForResume(id);
+ },
+ expunge: function(id) {
+ abort(id);
+ handler._maybeDeletePersistedChunkData(id);
+ handler._clearXhrs(id);
+ super_.expunge(id);
+ }
+ };
+ });
+ qq.extend(this, {
+ clearCachedChunk: function(id, chunkIdx) {
+ delete handler._getFileState(id).temp.cachedChunks[chunkIdx];
+ },
+ clearXhr: function(id, chunkIdx) {
+ var tempState = handler._getFileState(id).temp;
+ if (tempState.xhrs) {
+ delete tempState.xhrs[chunkIdx];
+ }
+ if (tempState.ajaxRequesters) {
+ delete tempState.ajaxRequesters[chunkIdx];
+ }
+ },
+ finalizeChunks: function(id, responseParser) {
+ var lastChunkIdx = handler._getTotalChunks(id) - 1, xhr = handler._getXhr(id, lastChunkIdx);
+ if (responseParser) {
+ return new qq.Promise().success(responseParser(xhr), xhr);
+ }
+ return new qq.Promise().success({}, xhr);
+ },
+ getFile: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).file;
+ },
+ getProxy: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).proxy;
+ },
+ getResumableFilesData: function() {
+ var resumableFilesData = [];
+ handler._iterateResumeRecords(function(key, uploadData) {
+ handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);
+ var data = {
+ name: uploadData.name,
+ remaining: uploadData.chunking.remaining,
+ size: uploadData.size,
+ uuid: uploadData.uuid
+ };
+ if (uploadData.key) {
+ data.key = uploadData.key;
+ }
+ resumableFilesData.push(data);
+ });
+ return resumableFilesData;
+ },
+ isResumable: function(id) {
+ return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;
+ },
+ moveInProgressToRemaining: function(id, optInProgress, optRemaining) {
+ var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress, remaining = optRemaining || handler._getFileState(id).chunking.remaining;
+ if (inProgress) {
+ log(qq.format("Moving these chunks from in-progress {}, to remaining.", JSON.stringify(inProgress)));
+ inProgress.reverse();
+ qq.each(inProgress, function(idx, chunkIdx) {
+ remaining.unshift(chunkIdx);
+ });
+ inProgress.length = 0;
+ }
+ },
+ pause: function(id) {
+ if (handler.isValid(id)) {
+ log(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.", id, getName(id)));
+ handler._getFileState(id).paused = true;
+ abort(id);
+ return true;
+ }
+ },
+ reevaluateChunking: function(id) {
+ if (chunking && handler.isValid(id)) {
+ var state = handler._getFileState(id), totalChunks, i;
+ delete state.chunking;
+ state.chunking = {};
+ totalChunks = handler._getTotalChunks(id);
+ if (totalChunks > 1 || chunking.mandatory) {
+ state.chunking.enabled = true;
+ state.chunking.parts = totalChunks;
+ state.chunking.remaining = [];
+ for (i = 0; i < totalChunks; i++) {
+ state.chunking.remaining.push(i);
+ }
+ handler._initTempState(id);
+ } else {
+ state.chunking.enabled = false;
+ }
+ }
+ },
+ updateBlob: function(id, newBlob) {
+ if (handler.isValid(id)) {
+ handler._getFileState(id).file = newBlob;
+ }
+ },
+ _clearXhrs: function(id) {
+ var tempState = handler._getFileState(id).temp;
+ qq.each(tempState.ajaxRequesters, function(chunkId) {
+ delete tempState.ajaxRequesters[chunkId];
+ });
+ qq.each(tempState.xhrs, function(chunkId) {
+ delete tempState.xhrs[chunkId];
+ });
+ },
+ _createXhr: function(id, optChunkIdx) {
+ return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());
+ },
+ _getAjaxRequester: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];
+ },
+ _getChunkData: function(id, chunkIndex) {
+ var chunkSize = chunking.partSize, fileSize = getSize(id), fileOrBlob = handler.getFile(id), startBytes = chunkSize * chunkIndex, endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize, totalChunks = handler._getTotalChunks(id), cachedChunks = this._getFileState(id).temp.cachedChunks, blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);
+ cachedChunks[chunkIndex] = blob;
+ return {
+ part: chunkIndex,
+ start: startBytes,
+ end: endBytes,
+ count: totalChunks,
+ blob: blob,
+ size: endBytes - startBytes
+ };
+ },
+ _getChunkDataForCallback: function(chunkData) {
+ return {
+ partIndex: chunkData.part,
+ startByte: chunkData.start + 1,
+ endByte: chunkData.end,
+ totalParts: chunkData.count
+ };
+ },
+ _getLocalStorageId: function(id) {
+ var formatVersion = "5.0", name = getName(id), size = getSize(id), chunkSize = chunking.partSize, endpoint = getEndpoint(id);
+ return qq.format("qq{}resume{}-{}-{}-{}-{}", namespace, formatVersion, name, size, chunkSize, endpoint);
+ },
+ _getMimeType: function(id) {
+ return handler.getFile(id).type;
+ },
+ _getPersistableData: function(id) {
+ return handler._getFileState(id).chunking;
+ },
+ _getTotalChunks: function(id) {
+ if (chunking) {
+ var fileSize = getSize(id), chunkSize = chunking.partSize;
+ return Math.ceil(fileSize / chunkSize);
+ }
+ },
+ _getXhr: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.xhrs[chunkIdx];
+ },
+ _getXhrs: function(id) {
+ return handler._getFileState(id).temp.xhrs;
+ },
+ _iterateResumeRecords: function(callback) {
+ if (resumeEnabled) {
+ qq.each(localStorage, function(key, item) {
+ if (key.indexOf(qq.format("qq{}resume", namespace)) === 0) {
+ var uploadData = JSON.parse(item);
+ callback(key, uploadData);
+ }
+ });
+ }
+ },
+ _initTempState: function(id) {
+ handler._getFileState(id).temp = {
+ ajaxRequesters: {},
+ chunkProgress: {},
+ xhrs: {},
+ cachedChunks: {}
+ };
+ },
+ _markNotResumable: function(id) {
+ handler._getFileState(id).notResumable = true;
+ },
+ _maybeDeletePersistedChunkData: function(id) {
+ var localStorageId;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ if (localStorageId && localStorage.getItem(localStorageId)) {
+ localStorage.removeItem(localStorageId);
+ return true;
+ }
+ }
+ return false;
+ },
+ _maybePrepareForResume: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && state.key === undefined) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = localStorage.getItem(localStorageId);
+ if (persistedData) {
+ persistedData = JSON.parse(persistedData);
+ if (getDataByUuid(persistedData.uuid)) {
+ handler._markNotResumable(id);
+ } else {
+ log(qq.format("Identified file with ID {} and name of {} as resumable.", id, getName(id)));
+ onUuidChanged(id, persistedData.uuid);
+ state.key = persistedData.key;
+ state.chunking = persistedData.chunking;
+ state.loaded = persistedData.loaded;
+ state.attemptingResume = true;
+ handler.moveInProgressToRemaining(id);
+ }
+ }
+ }
+ },
+ _maybePersistChunkedState: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = {
+ name: getName(id),
+ size: getSize(id),
+ uuid: getUuid(id),
+ key: state.key,
+ chunking: state.chunking,
+ loaded: state.loaded,
+ lastUpdated: Date.now()
+ };
+ try {
+ localStorage.setItem(localStorageId, JSON.stringify(persistedData));
+ } catch (error) {
+ log(qq.format("Unable to save resume data for '{}' due to error: '{}'.", id, error.toString()), "warn");
+ }
+ }
+ },
+ _registerProgressHandler: function(id, chunkIdx, chunkSize) {
+ var xhr = handler._getXhr(id, chunkIdx), name = getName(id), progressCalculator = {
+ simple: function(loaded, total) {
+ var fileSize = getSize(id);
+ if (loaded === total) {
+ onProgress(id, name, fileSize, fileSize);
+ } else {
+ onProgress(id, name, loaded >= fileSize ? fileSize - 1 : loaded, fileSize);
+ }
+ },
+ chunked: function(loaded, total) {
+ var chunkProgress = handler._getFileState(id).temp.chunkProgress, totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded, loadedForRequest = loaded, totalForRequest = total, totalFileSize = getSize(id), estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize), totalLoadedForFile = totalSuccessfullyLoadedForFile;
+ chunkProgress[chunkIdx] = estActualChunkLoaded;
+ qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {
+ totalLoadedForFile += chunkLoaded;
+ });
+ onProgress(id, name, totalLoadedForFile, totalFileSize);
+ }
+ };
+ xhr.upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ var type = chunkSize == null ? "simple" : "chunked";
+ progressCalculator[type](e.loaded, e.total);
+ }
+ };
+ },
+ _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {
+ var xhrsId = optChunkIdx == null ? -1 : optChunkIdx, tempState = handler._getFileState(id).temp;
+ tempState.xhrs = tempState.xhrs || {};
+ tempState.ajaxRequesters = tempState.ajaxRequesters || {};
+ tempState.xhrs[xhrsId] = xhr;
+ if (optAjaxRequester) {
+ tempState.ajaxRequesters[xhrsId] = optAjaxRequester;
+ }
+ return xhr;
+ },
+ _removeExpiredChunkingRecords: function() {
+ var expirationDays = resume.recordsExpireIn;
+ handler._iterateResumeRecords(function(key, uploadData) {
+ var expirationDate = new Date(uploadData.lastUpdated);
+ expirationDate.setDate(expirationDate.getDate() + expirationDays);
+ if (expirationDate.getTime() <= Date.now()) {
+ log("Removing expired resume record with key " + key);
+ localStorage.removeItem(key);
+ }
+ });
+ },
+ _shouldChunkThisFile: function(id) {
+ var state = handler._getFileState(id);
+ if (!state.chunking) {
+ handler.reevaluateChunking(id);
+ }
+ return state.chunking.enabled;
+ }
+ });
+ };
+ qq.DeleteFileAjaxRequester = function(o) {
+ "use strict";
+ var requester, options = {
+ method: "DELETE",
+ uuidParamName: "qquuid",
+ endpointStore: {},
+ maxConnections: 3,
+ customHeaders: function(id) {
+ return {};
+ },
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {}
+ };
+ qq.extend(options, o);
+ function getMandatedParams() {
+ if (options.method.toUpperCase() === "POST") {
+ return {
+ _method: "DELETE"
+ };
+ }
+ return {};
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "POST", "DELETE" ],
+ method: options.method,
+ endpointStore: options.endpointStore,
+ paramsStore: options.paramsStore,
+ mandatedParams: getMandatedParams(),
+ maxConnections: options.maxConnections,
+ customHeaders: function(id) {
+ return options.customHeaders.get(id);
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendDelete: function(id, uuid, additionalMandatedParams) {
+ var additionalOptions = additionalMandatedParams || {};
+ options.log("Submitting delete file request for " + id);
+ if (options.method === "DELETE") {
+ requester.initTransport(id).withPath(uuid).withParams(additionalOptions).send();
+ } else {
+ additionalOptions[options.uuidParamName] = uuid;
+ requester.initTransport(id).withParams(additionalOptions).send();
+ }
+ }
+ });
+ };
+ (function() {
+ function detectSubsampling(img) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, canvas = document.createElement("canvas"), ctx;
+ if (iw * ih > 1024 * 1024) {
+ canvas.width = canvas.height = 1;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, -iw + 1, 0);
+ return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+ } else {
+ return false;
+ }
+ }
+ function detectVerticalSquash(img, iw, ih) {
+ var canvas = document.createElement("canvas"), sy = 0, ey = ih, py = ih, ctx, data, alpha, ratio;
+ canvas.width = 1;
+ canvas.height = ih;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, 0, 0);
+ data = ctx.getImageData(0, 0, 1, ih).data;
+ while (py > sy) {
+ alpha = data[(py - 1) * 4 + 3];
+ if (alpha === 0) {
+ ey = py;
+ } else {
+ sy = py;
+ }
+ py = ey + sy >> 1;
+ }
+ ratio = py / ih;
+ return ratio === 0 ? 1 : ratio;
+ }
+ function renderImageToDataURL(img, blob, options, doSquash) {
+ var canvas = document.createElement("canvas"), mime = options.mime || "image/jpeg", promise = new qq.Promise();
+ renderImageToCanvas(img, blob, canvas, options, doSquash).then(function() {
+ promise.success(canvas.toDataURL(mime, options.quality || .8));
+ });
+ return promise;
+ }
+ function maybeCalculateDownsampledDimensions(spec) {
+ var maxPixels = 5241e3;
+ if (!qq.ios()) {
+ throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");
+ }
+ if (spec.origHeight * spec.origWidth > maxPixels) {
+ return {
+ newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),
+ newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))
+ };
+ }
+ }
+ function renderImageToCanvas(img, blob, canvas, options, doSquash) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, width = options.width, height = options.height, ctx = canvas.getContext("2d"), promise = new qq.Promise(), modifiedDimensions;
+ ctx.save();
+ if (options.resize) {
+ return renderImageToCanvasWithCustomResizer({
+ blob: blob,
+ canvas: canvas,
+ image: img,
+ imageHeight: ih,
+ imageWidth: iw,
+ orientation: options.orientation,
+ resize: options.resize,
+ targetHeight: height,
+ targetWidth: width
+ });
+ }
+ if (!qq.supportedFeatures.unlimitedScaledImageSize) {
+ modifiedDimensions = maybeCalculateDownsampledDimensions({
+ origWidth: width,
+ origHeight: height
+ });
+ if (modifiedDimensions) {
+ qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h", width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight), "warn");
+ width = modifiedDimensions.newWidth;
+ height = modifiedDimensions.newHeight;
+ }
+ }
+ transformCoordinate(canvas, width, height, options.orientation);
+ if (qq.ios()) {
+ (function() {
+ if (detectSubsampling(img)) {
+ iw /= 2;
+ ih /= 2;
+ }
+ var d = 1024, tmpCanvas = document.createElement("canvas"), vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1, dw = Math.ceil(d * width / iw), dh = Math.ceil(d * height / ih / vertSquashRatio), sy = 0, dy = 0, tmpCtx, sx, dx;
+ tmpCanvas.width = tmpCanvas.height = d;
+ tmpCtx = tmpCanvas.getContext("2d");
+ while (sy < ih) {
+ sx = 0;
+ dx = 0;
+ while (sx < iw) {
+ tmpCtx.clearRect(0, 0, d, d);
+ tmpCtx.drawImage(img, -sx, -sy);
+ ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);
+ sx += d;
+ dx += dw;
+ }
+ sy += d;
+ dy += dh;
+ }
+ ctx.restore();
+ tmpCanvas = tmpCtx = null;
+ })();
+ } else {
+ ctx.drawImage(img, 0, 0, width, height);
+ }
+ canvas.qqImageRendered && canvas.qqImageRendered();
+ promise.success();
+ return promise;
+ }
+ function renderImageToCanvasWithCustomResizer(resizeInfo) {
+ var blob = resizeInfo.blob, image = resizeInfo.image, imageHeight = resizeInfo.imageHeight, imageWidth = resizeInfo.imageWidth, orientation = resizeInfo.orientation, promise = new qq.Promise(), resize = resizeInfo.resize, sourceCanvas = document.createElement("canvas"), sourceCanvasContext = sourceCanvas.getContext("2d"), targetCanvas = resizeInfo.canvas, targetHeight = resizeInfo.targetHeight, targetWidth = resizeInfo.targetWidth;
+ transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);
+ targetCanvas.height = targetHeight;
+ targetCanvas.width = targetWidth;
+ sourceCanvasContext.drawImage(image, 0, 0);
+ resize({
+ blob: blob,
+ height: targetHeight,
+ image: image,
+ sourceCanvas: sourceCanvas,
+ targetCanvas: targetCanvas,
+ width: targetWidth
+ }).then(function success() {
+ targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();
+ promise.success();
+ }, promise.failure);
+ return promise;
+ }
+ function transformCoordinate(canvas, width, height, orientation) {
+ switch (orientation) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ canvas.width = height;
+ canvas.height = width;
+ break;
+
+ default:
+ canvas.width = width;
+ canvas.height = height;
+ }
+ var ctx = canvas.getContext("2d");
+ switch (orientation) {
+ case 2:
+ ctx.translate(width, 0);
+ ctx.scale(-1, 1);
+ break;
+
+ case 3:
+ ctx.translate(width, height);
+ ctx.rotate(Math.PI);
+ break;
+
+ case 4:
+ ctx.translate(0, height);
+ ctx.scale(1, -1);
+ break;
+
+ case 5:
+ ctx.rotate(.5 * Math.PI);
+ ctx.scale(1, -1);
+ break;
+
+ case 6:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(0, -height);
+ break;
+
+ case 7:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(width, -height);
+ ctx.scale(-1, 1);
+ break;
+
+ case 8:
+ ctx.rotate(-.5 * Math.PI);
+ ctx.translate(-width, 0);
+ break;
+
+ default:
+ break;
+ }
+ }
+ function MegaPixImage(srcImage, errorCallback) {
+ var self = this;
+ if (window.Blob && srcImage instanceof Blob) {
+ (function() {
+ var img = new Image(), URL = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (!URL) {
+ throw Error("No createObjectURL function found to create blob url");
+ }
+ img.src = URL.createObjectURL(srcImage);
+ self.blob = srcImage;
+ srcImage = img;
+ })();
+ }
+ if (!srcImage.naturalWidth && !srcImage.naturalHeight) {
+ srcImage.onload = function() {
+ var listeners = self.imageLoadListeners;
+ if (listeners) {
+ self.imageLoadListeners = null;
+ setTimeout(function() {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i]();
+ }
+ }, 0);
+ }
+ };
+ srcImage.onerror = errorCallback;
+ this.imageLoadListeners = [];
+ }
+ this.srcImage = srcImage;
+ }
+ MegaPixImage.prototype.render = function(target, options) {
+ options = options || {};
+ var self = this, imgWidth = this.srcImage.naturalWidth, imgHeight = this.srcImage.naturalHeight, width = options.width, height = options.height, maxWidth = options.maxWidth, maxHeight = options.maxHeight, doSquash = !this.blob || this.blob.type === "image/jpeg", tagName = target.tagName.toLowerCase(), opt;
+ if (this.imageLoadListeners) {
+ this.imageLoadListeners.push(function() {
+ self.render(target, options);
+ });
+ return;
+ }
+ if (width && !height) {
+ height = imgHeight * width / imgWidth << 0;
+ } else if (height && !width) {
+ width = imgWidth * height / imgHeight << 0;
+ } else {
+ width = imgWidth;
+ height = imgHeight;
+ }
+ if (maxWidth && width > maxWidth) {
+ width = maxWidth;
+ height = imgHeight * width / imgWidth << 0;
+ }
+ if (maxHeight && height > maxHeight) {
+ height = maxHeight;
+ width = imgWidth * height / imgHeight << 0;
+ }
+ opt = {
+ width: width,
+ height: height
+ }, qq.each(options, function(optionsKey, optionsValue) {
+ opt[optionsKey] = optionsValue;
+ });
+ if (tagName === "img") {
+ (function() {
+ var oldTargetSrc = target.src;
+ renderImageToDataURL(self.srcImage, self.blob, opt, doSquash).then(function(dataUri) {
+ target.src = dataUri;
+ oldTargetSrc === target.src && target.onload();
+ });
+ })();
+ } else if (tagName === "canvas") {
+ renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);
+ }
+ if (typeof this.onrender === "function") {
+ this.onrender(target);
+ }
+ };
+ qq.MegaPixImage = MegaPixImage;
+ })();
+ qq.ImageGenerator = function(log) {
+ "use strict";
+ function isImg(el) {
+ return el.tagName.toLowerCase() === "img";
+ }
+ function isCanvas(el) {
+ return el.tagName.toLowerCase() === "canvas";
+ }
+ function isImgCorsSupported() {
+ return new Image().crossOrigin !== undefined;
+ }
+ function isCanvasSupported() {
+ var canvas = document.createElement("canvas");
+ return canvas.getContext && canvas.getContext("2d");
+ }
+ function determineMimeOfFileName(nameWithPath) {
+ var pathSegments = nameWithPath.split("/"), name = pathSegments[pathSegments.length - 1].split("?")[0], extension = qq.getExtension(name);
+ extension = extension && extension.toLowerCase();
+ switch (extension) {
+ case "jpeg":
+ case "jpg":
+ return "image/jpeg";
+
+ case "png":
+ return "image/png";
+
+ case "bmp":
+ return "image/bmp";
+
+ case "gif":
+ return "image/gif";
+
+ case "tiff":
+ case "tif":
+ return "image/tiff";
+ }
+ }
+ function isCrossOrigin(url) {
+ var targetAnchor = document.createElement("a"), targetProtocol, targetHostname, targetPort;
+ targetAnchor.href = url;
+ targetProtocol = targetAnchor.protocol;
+ targetPort = targetAnchor.port;
+ targetHostname = targetAnchor.hostname;
+ if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {
+ return true;
+ }
+ if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {
+ return true;
+ }
+ if (targetPort !== window.location.port && !qq.ie()) {
+ return true;
+ }
+ return false;
+ }
+ function registerImgLoadListeners(img, promise) {
+ img.onload = function() {
+ img.onload = null;
+ img.onerror = null;
+ promise.success(img);
+ };
+ img.onerror = function() {
+ img.onload = null;
+ img.onerror = null;
+ log("Problem drawing thumbnail!", "error");
+ promise.failure(img, "Problem drawing thumbnail!");
+ };
+ }
+ function registerCanvasDrawImageListener(canvas, promise) {
+ canvas.qqImageRendered = function() {
+ promise.success(canvas);
+ };
+ }
+ function registerThumbnailRenderedListener(imgOrCanvas, promise) {
+ var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);
+ if (isImg(imgOrCanvas)) {
+ registerImgLoadListeners(imgOrCanvas, promise);
+ } else if (isCanvas(imgOrCanvas)) {
+ registerCanvasDrawImageListener(imgOrCanvas, promise);
+ } else {
+ promise.failure(imgOrCanvas);
+ log(qq.format("Element container of type {} is not supported!", imgOrCanvas.tagName), "error");
+ }
+ return registered;
+ }
+ function draw(fileOrBlob, container, options) {
+ var drawPreview = new qq.Promise(), identifier = new qq.Identify(fileOrBlob, log), maxSize = options.maxSize, orient = options.orient == null ? true : options.orient, megapixErrorHandler = function() {
+ container.onerror = null;
+ container.onload = null;
+ log("Could not render preview, file may be too large!", "error");
+ drawPreview.failure(container, "Browser cannot render image!");
+ };
+ identifier.isPreviewable().then(function(mime) {
+ var dummyExif = {
+ parse: function() {
+ return new qq.Promise().success();
+ }
+ }, exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif, mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);
+ if (registerThumbnailRenderedListener(container, drawPreview)) {
+ exif.parse().then(function(exif) {
+ var orientation = exif && exif.Orientation;
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ orientation: orientation,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ }, function(failureMsg) {
+ log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", failureMsg));
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ });
+ }
+ }, function() {
+ log("Not previewable");
+ drawPreview.failure(container, "Not previewable");
+ });
+ return drawPreview;
+ }
+ function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {
+ var tempImg = new Image(), tempImgRender = new qq.Promise();
+ registerThumbnailRenderedListener(tempImg, tempImgRender);
+ if (isCrossOrigin(url)) {
+ tempImg.crossOrigin = "anonymous";
+ }
+ tempImg.src = url;
+ tempImgRender.then(function rendered() {
+ registerThumbnailRenderedListener(canvasOrImg, draw);
+ var mpImg = new qq.MegaPixImage(tempImg);
+ mpImg.render(canvasOrImg, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: determineMimeOfFileName(url),
+ resize: customResizeFunction
+ });
+ }, draw.failure);
+ }
+ function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {
+ registerThumbnailRenderedListener(img, draw);
+ qq(img).css({
+ maxWidth: maxSize + "px",
+ maxHeight: maxSize + "px"
+ });
+ img.src = url;
+ }
+ function drawFromUrl(url, container, options) {
+ var draw = new qq.Promise(), scale = options.scale, maxSize = scale ? options.maxSize : null;
+ if (scale && isImg(container)) {
+ if (isCanvasSupported()) {
+ if (isCrossOrigin(url) && !isImgCorsSupported()) {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ } else {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ }
+ } else {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ }
+ } else if (isCanvas(container)) {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ } else if (registerThumbnailRenderedListener(container, draw)) {
+ container.src = url;
+ }
+ return draw;
+ }
+ qq.extend(this, {
+ generate: function(fileBlobOrUrl, container, options) {
+ if (qq.isString(fileBlobOrUrl)) {
+ log("Attempting to update thumbnail based on server response.");
+ return drawFromUrl(fileBlobOrUrl, container, options || {});
+ } else {
+ log("Attempting to draw client-side image preview.");
+ return draw(fileBlobOrUrl, container, options || {});
+ }
+ }
+ });
+ this._testing = {};
+ this._testing.isImg = isImg;
+ this._testing.isCanvas = isCanvas;
+ this._testing.isCrossOrigin = isCrossOrigin;
+ this._testing.determineMimeOfFileName = determineMimeOfFileName;
+ };
+ qq.Exif = function(fileOrBlob, log) {
+ "use strict";
+ var TAG_IDS = [ 274 ], TAG_INFO = {
+ 274: {
+ name: "Orientation",
+ bytes: 2
+ }
+ };
+ function parseLittleEndian(hex) {
+ var result = 0, pow = 0;
+ while (hex.length > 0) {
+ result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);
+ hex = hex.substring(2, hex.length);
+ pow += 8;
+ }
+ return result;
+ }
+ function seekToApp1(offset, promise) {
+ var theOffset = offset, thePromise = promise;
+ if (theOffset === undefined) {
+ theOffset = 2;
+ thePromise = new qq.Promise();
+ }
+ qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {
+ var match = /^ffe([0-9])/.exec(hex), segmentLength;
+ if (match) {
+ if (match[1] !== "1") {
+ segmentLength = parseInt(hex.slice(4, 8), 16);
+ seekToApp1(theOffset + segmentLength + 2, thePromise);
+ } else {
+ thePromise.success(theOffset);
+ }
+ } else {
+ thePromise.failure("No EXIF header to be found!");
+ }
+ });
+ return thePromise;
+ }
+ function getApp1Offset() {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {
+ if (hex.indexOf("ffd8") !== 0) {
+ promise.failure("Not a valid JPEG!");
+ } else {
+ seekToApp1().then(function(offset) {
+ promise.success(offset);
+ }, function(error) {
+ promise.failure(error);
+ });
+ }
+ });
+ return promise;
+ }
+ function isLittleEndian(app1Start) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {
+ promise.success(hex === "4949");
+ });
+ return promise;
+ }
+ function getDirEntryCount(app1Start, littleEndian) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {
+ if (littleEndian) {
+ return promise.success(parseLittleEndian(hex));
+ } else {
+ promise.success(parseInt(hex, 16));
+ }
+ });
+ return promise;
+ }
+ function getIfd(app1Start, dirEntries) {
+ var offset = app1Start + 20, bytes = dirEntries * 12;
+ return qq.readBlobToHex(fileOrBlob, offset, bytes);
+ }
+ function getDirEntries(ifdHex) {
+ var entries = [], offset = 0;
+ while (offset + 24 <= ifdHex.length) {
+ entries.push(ifdHex.slice(offset, offset + 24));
+ offset += 24;
+ }
+ return entries;
+ }
+ function getTagValues(littleEndian, dirEntries) {
+ var TAG_VAL_OFFSET = 16, tagsToFind = qq.extend([], TAG_IDS), vals = {};
+ qq.each(dirEntries, function(idx, entry) {
+ var idHex = entry.slice(0, 4), id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16), tagsToFindIdx = tagsToFind.indexOf(id), tagValHex, tagName, tagValLength;
+ if (tagsToFindIdx >= 0) {
+ tagName = TAG_INFO[id].name;
+ tagValLength = TAG_INFO[id].bytes;
+ tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + tagValLength * 2);
+ vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);
+ tagsToFind.splice(tagsToFindIdx, 1);
+ }
+ if (tagsToFind.length === 0) {
+ return false;
+ }
+ });
+ return vals;
+ }
+ qq.extend(this, {
+ parse: function() {
+ var parser = new qq.Promise(), onParseFailure = function(message) {
+ log(qq.format("EXIF header parse failed: '{}' ", message));
+ parser.failure(message);
+ };
+ getApp1Offset().then(function(app1Offset) {
+ log(qq.format("Moving forward with EXIF header parsing for '{}'", fileOrBlob.name === undefined ? "blob" : fileOrBlob.name));
+ isLittleEndian(app1Offset).then(function(littleEndian) {
+ log(qq.format("EXIF Byte order is {} endian", littleEndian ? "little" : "big"));
+ getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {
+ log(qq.format("Found {} APP1 directory entries", dirEntryCount));
+ getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {
+ var dirEntries = getDirEntries(ifdHex), tagValues = getTagValues(littleEndian, dirEntries);
+ log("Successfully parsed some EXIF tags");
+ parser.success(tagValues);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ return parser;
+ }
+ });
+ this._testing = {};
+ this._testing.parseLittleEndian = parseLittleEndian;
+ };
+ qq.Identify = function(fileOrBlob, log) {
+ "use strict";
+ function isIdentifiable(magicBytes, questionableBytes) {
+ var identifiable = false, magicBytesEntries = [].concat(magicBytes);
+ qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {
+ if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {
+ identifiable = true;
+ return false;
+ }
+ });
+ return identifiable;
+ }
+ qq.extend(this, {
+ isPreviewable: function() {
+ var self = this, identifier = new qq.Promise(), previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ log(qq.format("Attempting to determine if {} can be rendered in this browser", name));
+ log("First pass: check type attribute of blob object.");
+ if (this.isPreviewableSync()) {
+ log("Second pass: check for magic bytes in file header.");
+ qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {
+ qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {
+ if (isIdentifiable(bytes, hex)) {
+ if (mime !== "image/tiff" || qq.supportedFeatures.tiffPreviews) {
+ previewable = true;
+ identifier.success(mime);
+ }
+ return false;
+ }
+ });
+ log(qq.format("'{}' is {} able to be rendered in this browser", name, previewable ? "" : "NOT"));
+ if (!previewable) {
+ identifier.failure();
+ }
+ }, function() {
+ log("Error reading file w/ name '" + name + "'. Not able to be rendered in this browser.");
+ identifier.failure();
+ });
+ } else {
+ identifier.failure();
+ }
+ return identifier;
+ },
+ isPreviewableSync: function() {
+ var fileMime = fileOrBlob.type, isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0, previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ if (isRecognizedImage) {
+ if (fileMime === "image/tiff") {
+ previewable = qq.supportedFeatures.tiffPreviews;
+ } else {
+ previewable = true;
+ }
+ }
+ !previewable && log(name + " is not previewable in this browser per the blob's type attr");
+ return previewable;
+ }
+ });
+ };
+ qq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {
+ "image/jpeg": "ffd8ff",
+ "image/gif": "474946",
+ "image/png": "89504e",
+ "image/bmp": "424d",
+ "image/tiff": [ "49492a00", "4d4d002a" ]
+ };
+ qq.ImageValidation = function(blob, log) {
+ "use strict";
+ function hasNonZeroLimits(limits) {
+ var atLeastOne = false;
+ qq.each(limits, function(limit, value) {
+ if (value > 0) {
+ atLeastOne = true;
+ return false;
+ }
+ });
+ return atLeastOne;
+ }
+ function getWidthHeight() {
+ var sizeDetermination = new qq.Promise();
+ new qq.Identify(blob, log).isPreviewable().then(function() {
+ var image = new Image(), url = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (url) {
+ image.onerror = function() {
+ log("Cannot determine dimensions for image. May be too large.", "error");
+ sizeDetermination.failure();
+ };
+ image.onload = function() {
+ sizeDetermination.success({
+ width: this.width,
+ height: this.height
+ });
+ };
+ image.src = url.createObjectURL(blob);
+ } else {
+ log("No createObjectURL function available to generate image URL!", "error");
+ sizeDetermination.failure();
+ }
+ }, sizeDetermination.failure);
+ return sizeDetermination;
+ }
+ function getFailingLimit(limits, dimensions) {
+ var failingLimit;
+ qq.each(limits, function(limitName, limitValue) {
+ if (limitValue > 0) {
+ var limitMatcher = /(max|min)(Width|Height)/.exec(limitName), dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1), actualValue = dimensions[dimensionPropName];
+ switch (limitMatcher[1]) {
+ case "min":
+ if (actualValue < limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+
+ case "max":
+ if (actualValue > limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+ }
+ }
+ });
+ return failingLimit;
+ }
+ this.validate = function(limits) {
+ var validationEffort = new qq.Promise();
+ log("Attempting to validate image.");
+ if (hasNonZeroLimits(limits)) {
+ getWidthHeight().then(function(dimensions) {
+ var failingLimit = getFailingLimit(limits, dimensions);
+ if (failingLimit) {
+ validationEffort.failure(failingLimit);
+ } else {
+ validationEffort.success();
+ }
+ }, validationEffort.success);
+ } else {
+ validationEffort.success();
+ }
+ return validationEffort;
+ };
+ };
+ qq.Session = function(spec) {
+ "use strict";
+ var options = {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ cors: {},
+ addFileRecord: function(sessionData) {},
+ log: function(message, level) {}
+ };
+ qq.extend(options, spec, true);
+ function isJsonResponseValid(response) {
+ if (qq.isArray(response)) {
+ return true;
+ }
+ options.log("Session response is not an array.", "error");
+ }
+ function handleFileItems(fileItems, success, xhrOrXdr, promise) {
+ var someItemsIgnored = false;
+ success = success && isJsonResponseValid(fileItems);
+ if (success) {
+ qq.each(fileItems, function(idx, fileItem) {
+ if (fileItem.uuid == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid UUID - ignoring.", idx), "error");
+ } else if (fileItem.name == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid name - ignoring.", idx), "error");
+ } else {
+ try {
+ options.addFileRecord(fileItem);
+ return true;
+ } catch (err) {
+ someItemsIgnored = true;
+ options.log(err.message, "error");
+ }
+ }
+ return false;
+ });
+ }
+ promise[success && !someItemsIgnored ? "success" : "failure"](fileItems, xhrOrXdr);
+ }
+ this.refresh = function() {
+ var refreshEffort = new qq.Promise(), refreshCompleteCallback = function(response, success, xhrOrXdr) {
+ handleFileItems(response, success, xhrOrXdr, refreshEffort);
+ }, requesterOptions = qq.extend({}, options), requester = new qq.SessionAjaxRequester(qq.extend(requesterOptions, {
+ onComplete: refreshCompleteCallback
+ }));
+ requester.queryServer();
+ return refreshEffort;
+ };
+ };
+ qq.SessionAjaxRequester = function(spec) {
+ "use strict";
+ var requester, options = {
+ endpoint: null,
+ customHeaders: {},
+ params: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ onComplete: function(response, success, xhrOrXdr) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, spec);
+ function onComplete(id, xhrOrXdr, isError) {
+ var response = null;
+ if (xhrOrXdr.responseText != null) {
+ try {
+ response = qq.parseJson(xhrOrXdr.responseText);
+ } catch (err) {
+ options.log("Problem parsing session response: " + err.message, "error");
+ isError = true;
+ }
+ }
+ options.onComplete(response, !isError, xhrOrXdr);
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: onComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ queryServer: function() {
+ var params = qq.extend({}, options.params);
+ options.log("Session query request.");
+ requester.initTransport("sessionRefresh").withParams(params).withCacheBuster().send();
+ }
+ });
+ };
+ qq.Scaler = function(spec, log) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizer, includeOriginal = spec.sendOriginal, orient = spec.orient, defaultType = spec.defaultType, defaultQuality = spec.defaultQuality / 100, failedToScaleText = spec.failureText, includeExif = spec.includeExif, sizes = this._getSortedSizes(spec.sizes);
+ qq.extend(this, {
+ enabled: qq.supportedFeatures.scaling && sizes.length > 0,
+ getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {
+ var self = this, records = [], originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData, identifier = new qq.Identify(originalBlob, log);
+ if (identifier.isPreviewableSync()) {
+ qq.each(sizes, function(idx, sizeRecord) {
+ var outputType = self._determineOutputType({
+ defaultType: defaultType,
+ requestedType: sizeRecord.type,
+ refType: originalBlob.type
+ });
+ records.push({
+ uuid: qq.getUniqueId(),
+ name: self._getName(originalFileName, {
+ name: sizeRecord.name,
+ type: outputType,
+ refType: originalBlob.type
+ }),
+ blob: new qq.BlobProxy(originalBlob, qq.bind(self._generateScaledImage, self, {
+ customResizeFunction: customResizeFunction,
+ maxSize: sizeRecord.maxSize,
+ orient: orient,
+ type: outputType,
+ quality: defaultQuality,
+ failedText: failedToScaleText,
+ includeExif: includeExif,
+ log: log
+ }))
+ });
+ });
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: includeOriginal ? originalBlob : null
+ });
+ } else {
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: originalBlob
+ });
+ }
+ return records;
+ },
+ handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {
+ var self = this, buttonId = file.qqButtonId || file.blob && file.blob.qqButtonId, scaledIds = [], originalId = null, addFileToHandler = api.addFileToHandler, uploadData = api.uploadData, paramsStore = api.paramsStore, proxyGroupId = qq.getUniqueId();
+ qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {
+ var blobSize = record.size, id;
+ if (record.blob instanceof qq.BlobProxy) {
+ blobSize = -1;
+ }
+ id = uploadData.addFile({
+ uuid: record.uuid,
+ name: record.name,
+ size: blobSize,
+ batchId: batchId,
+ proxyGroupId: proxyGroupId
+ });
+ if (record.blob instanceof qq.BlobProxy) {
+ scaledIds.push(id);
+ } else {
+ originalId = id;
+ }
+ if (record.blob) {
+ addFileToHandler(id, record.blob);
+ fileList.push({
+ id: id,
+ file: record.blob
+ });
+ } else {
+ uploadData.setStatus(id, qq.status.REJECTED);
+ }
+ });
+ if (originalId !== null) {
+ qq.each(scaledIds, function(idx, scaledId) {
+ var params = {
+ qqparentuuid: uploadData.retrieve({
+ id: originalId
+ }).uuid,
+ qqparentsize: uploadData.retrieve({
+ id: originalId
+ }).size
+ };
+ params[uuidParamName] = uploadData.retrieve({
+ id: scaledId
+ }).uuid;
+ uploadData.setParentId(scaledId, originalId);
+ paramsStore.addReadOnly(scaledId, params);
+ });
+ if (scaledIds.length) {
+ (function() {
+ var param = {};
+ param[uuidParamName] = uploadData.retrieve({
+ id: originalId
+ }).uuid;
+ paramsStore.addReadOnly(originalId, param);
+ })();
+ }
+ }
+ }
+ });
+ };
+ qq.extend(qq.Scaler.prototype, {
+ scaleImage: function(id, specs, api) {
+ "use strict";
+ if (!qq.supportedFeatures.scaling) {
+ throw new qq.Error("Scaling is not supported in this browser!");
+ }
+ var scalingEffort = new qq.Promise(), log = api.log, file = api.getFile(id), uploadData = api.uploadData.retrieve({
+ id: id
+ }), name = uploadData && uploadData.name, uuid = uploadData && uploadData.uuid, scalingOptions = {
+ customResizer: specs.customResizer,
+ sendOriginal: false,
+ orient: specs.orient,
+ defaultType: specs.type || null,
+ defaultQuality: specs.quality,
+ failedToScaleText: "Unable to scale",
+ sizes: [ {
+ name: "",
+ maxSize: specs.maxSize
+ } ]
+ }, scaler = new qq.Scaler(scalingOptions, log);
+ if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {
+ scalingEffort.failure();
+ log("Could not generate requested scaled image for " + id + ". " + "Scaling is either not possible in this browser, or the file could not be located.", "error");
+ } else {
+ qq.bind(function() {
+ var record = scaler.getFileRecords(uuid, name, file)[0];
+ if (record && record.blob instanceof qq.BlobProxy) {
+ record.blob.create().then(scalingEffort.success, scalingEffort.failure);
+ } else {
+ log(id + " is not a scalable image!", "error");
+ scalingEffort.failure();
+ }
+ }, this)();
+ }
+ return scalingEffort;
+ },
+ _determineOutputType: function(spec) {
+ "use strict";
+ var requestedType = spec.requestedType, defaultType = spec.defaultType, referenceType = spec.refType;
+ if (!defaultType && !requestedType) {
+ if (referenceType !== "image/jpeg") {
+ return "image/png";
+ }
+ return referenceType;
+ }
+ if (!requestedType) {
+ return defaultType;
+ }
+ if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {
+ if (requestedType === "image/tiff") {
+ return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;
+ }
+ return requestedType;
+ }
+ return defaultType;
+ },
+ _getName: function(originalName, scaledVersionProperties) {
+ "use strict";
+ var startOfExt = originalName.lastIndexOf("."), versionType = scaledVersionProperties.type || "image/png", referenceType = scaledVersionProperties.refType, scaledName = "", scaledExt = qq.getExtension(originalName), nameAppendage = "";
+ if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {
+ nameAppendage = " (" + scaledVersionProperties.name + ")";
+ }
+ if (startOfExt >= 0) {
+ scaledName = originalName.substr(0, startOfExt);
+ if (referenceType !== versionType) {
+ scaledExt = versionType.split("/")[1];
+ }
+ scaledName += nameAppendage + "." + scaledExt;
+ } else {
+ scaledName = originalName + nameAppendage;
+ }
+ return scaledName;
+ },
+ _getSortedSizes: function(sizes) {
+ "use strict";
+ sizes = qq.extend([], sizes);
+ return sizes.sort(function(a, b) {
+ if (a.maxSize > b.maxSize) {
+ return 1;
+ }
+ if (a.maxSize < b.maxSize) {
+ return -1;
+ }
+ return 0;
+ });
+ },
+ _generateScaledImage: function(spec, sourceFile) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizeFunction, log = spec.log, maxSize = spec.maxSize, orient = spec.orient, type = spec.type, quality = spec.quality, failedText = spec.failedText, includeExif = spec.includeExif && sourceFile.type === "image/jpeg" && type === "image/jpeg", scalingEffort = new qq.Promise(), imageGenerator = new qq.ImageGenerator(log), canvas = document.createElement("canvas");
+ log("Attempting to generate scaled version for " + sourceFile.name);
+ imageGenerator.generate(sourceFile, canvas, {
+ maxSize: maxSize,
+ orient: orient,
+ customResizeFunction: customResizeFunction
+ }).then(function() {
+ var scaledImageDataUri = canvas.toDataURL(type, quality), signalSuccess = function() {
+ log("Success generating scaled version for " + sourceFile.name);
+ var blob = qq.dataUriToBlob(scaledImageDataUri);
+ scalingEffort.success(blob);
+ };
+ if (includeExif) {
+ self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {
+ scaledImageDataUri = scaledImageDataUriWithExif;
+ signalSuccess();
+ }, function() {
+ log("Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.", "error");
+ signalSuccess();
+ });
+ } else {
+ signalSuccess();
+ }
+ }, function() {
+ log("Failed attempt to generate scaled version for " + sourceFile.name, "error");
+ scalingEffort.failure(failedText);
+ });
+ return scalingEffort;
+ },
+ _insertExifHeader: function(originalImage, scaledImageDataUri, log) {
+ "use strict";
+ var reader = new FileReader(), insertionEffort = new qq.Promise(), originalImageDataUri = "";
+ reader.onload = function() {
+ originalImageDataUri = reader.result;
+ insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));
+ };
+ reader.onerror = function() {
+ log("Problem reading " + originalImage.name + " during attempt to transfer EXIF data to scaled version.", "error");
+ insertionEffort.failure();
+ };
+ reader.readAsDataURL(originalImage);
+ return insertionEffort;
+ },
+ _dataUriToBlob: function(dataUri) {
+ "use strict";
+ var byteString, mimeString, arrayBuffer, intArray;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return this._createBlob(arrayBuffer, mimeString);
+ },
+ _createBlob: function(data, mime) {
+ "use strict";
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }
+ });
+ qq.ExifRestorer = function() {
+ var ExifRestorer = {};
+ ExifRestorer.KEY_STR = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + "ghijklmnopqrstuv" + "wxyz0123456789+/" + "=";
+ ExifRestorer.encode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0;
+ do {
+ chr1 = input[i++];
+ chr2 = input[i++];
+ chr3 = input[i++];
+ enc1 = chr1 >> 2;
+ enc2 = (chr1 & 3) << 4 | chr2 >> 4;
+ enc3 = (chr2 & 15) << 2 | chr3 >> 6;
+ enc4 = chr3 & 63;
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+ output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4);
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return output;
+ };
+ ExifRestorer.restore = function(origFileBase64, resizedFileBase64) {
+ var expectedBase64Header = "data:image/jpeg;base64,";
+ if (!origFileBase64.match(expectedBase64Header)) {
+ return resizedFileBase64;
+ }
+ var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, ""));
+ var segments = this.slice2Segments(rawImage);
+ var image = this.exifManipulation(resizedFileBase64, segments);
+ return expectedBase64Header + this.encode64(image);
+ };
+ ExifRestorer.exifManipulation = function(resizedFileBase64, segments) {
+ var exifArray = this.getExifArray(segments), newImageArray = this.insertExif(resizedFileBase64, exifArray), aBuffer = new Uint8Array(newImageArray);
+ return aBuffer;
+ };
+ ExifRestorer.getExifArray = function(segments) {
+ var seg;
+ for (var x = 0; x < segments.length; x++) {
+ seg = segments[x];
+ if (seg[0] == 255 & seg[1] == 225) {
+ return seg;
+ }
+ }
+ return [];
+ };
+ ExifRestorer.insertExif = function(resizedFileBase64, exifArray) {
+ var imageData = resizedFileBase64.replace("data:image/jpeg;base64,", ""), buf = this.decode64(imageData), separatePoint = buf.indexOf(255, 3), mae = buf.slice(0, separatePoint), ato = buf.slice(separatePoint), array = mae;
+ array = array.concat(exifArray);
+ array = array.concat(ato);
+ return array;
+ };
+ ExifRestorer.slice2Segments = function(rawImageArray) {
+ var head = 0, segments = [];
+ while (1) {
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218) {
+ break;
+ }
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216) {
+ head += 2;
+ } else {
+ var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3], endPoint = head + length + 2, seg = rawImageArray.slice(head, endPoint);
+ segments.push(seg);
+ head = endPoint;
+ }
+ if (head > rawImageArray.length) {
+ break;
+ }
+ }
+ return segments;
+ };
+ ExifRestorer.decode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0, buf = [];
+ var base64test = /[^A-Za-z0-9\+\/\=]/g;
+ if (base64test.exec(input)) {
+ throw new Error("There were invalid base64 characters in the input text. " + "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");
+ }
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+ do {
+ enc1 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc2 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc3 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc4 = this.KEY_STR.indexOf(input.charAt(i++));
+ chr1 = enc1 << 2 | enc2 >> 4;
+ chr2 = (enc2 & 15) << 4 | enc3 >> 2;
+ chr3 = (enc3 & 3) << 6 | enc4;
+ buf.push(chr1);
+ if (enc3 != 64) {
+ buf.push(chr2);
+ }
+ if (enc4 != 64) {
+ buf.push(chr3);
+ }
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return buf;
+ };
+ return ExifRestorer;
+ }();
+ qq.TotalProgress = function(callback, getSize) {
+ "use strict";
+ var perFileProgress = {}, totalLoaded = 0, totalSize = 0, lastLoadedSent = -1, lastTotalSent = -1, callbackProxy = function(loaded, total) {
+ if (loaded !== lastLoadedSent || total !== lastTotalSent) {
+ callback(loaded, total);
+ }
+ lastLoadedSent = loaded;
+ lastTotalSent = total;
+ }, noRetryableFiles = function(failed, retryable) {
+ var none = true;
+ qq.each(failed, function(idx, failedId) {
+ if (qq.indexOf(retryable, failedId) >= 0) {
+ none = false;
+ return false;
+ }
+ });
+ return none;
+ }, onCancel = function(id) {
+ updateTotalProgress(id, -1, -1);
+ delete perFileProgress[id];
+ }, onAllComplete = function(successful, failed, retryable) {
+ if (failed.length === 0 || noRetryableFiles(failed, retryable)) {
+ callbackProxy(totalSize, totalSize);
+ this.reset();
+ }
+ }, onNew = function(id) {
+ var size = getSize(id);
+ if (size > 0) {
+ updateTotalProgress(id, 0, size);
+ perFileProgress[id] = {
+ loaded: 0,
+ total: size
+ };
+ }
+ }, updateTotalProgress = function(id, newLoaded, newTotal) {
+ var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0, oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;
+ if (newLoaded === -1 && newTotal === -1) {
+ totalLoaded -= oldLoaded;
+ totalSize -= oldTotal;
+ } else {
+ if (newLoaded) {
+ totalLoaded += newLoaded - oldLoaded;
+ }
+ if (newTotal) {
+ totalSize += newTotal - oldTotal;
+ }
+ }
+ callbackProxy(totalLoaded, totalSize);
+ };
+ qq.extend(this, {
+ onAllComplete: onAllComplete,
+ onStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {
+ onCancel(id);
+ } else if (newStatus === qq.status.SUBMITTING) {
+ onNew(id);
+ }
+ },
+ onIndividualProgress: function(id, loaded, total) {
+ updateTotalProgress(id, loaded, total);
+ perFileProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onNewSize: function(id) {
+ onNew(id);
+ },
+ reset: function() {
+ perFileProgress = {};
+ totalLoaded = 0;
+ totalSize = 0;
+ }
+ });
+ };
+ qq.PasteSupport = function(o) {
+ "use strict";
+ var options, detachPasteHandler;
+ options = {
+ targetElement: null,
+ callbacks: {
+ log: function(message, level) {},
+ pasteReceived: function(blob) {}
+ }
+ };
+ function isImage(item) {
+ return item.type && item.type.indexOf("image/") === 0;
+ }
+ function registerPasteHandler() {
+ detachPasteHandler = qq(options.targetElement).attach("paste", function(event) {
+ var clipboardData = event.clipboardData;
+ if (clipboardData) {
+ qq.each(clipboardData.items, function(idx, item) {
+ if (isImage(item)) {
+ var blob = item.getAsFile();
+ options.callbacks.pasteReceived(blob);
+ }
+ });
+ }
+ });
+ }
+ function unregisterPasteHandler() {
+ if (detachPasteHandler) {
+ detachPasteHandler();
+ }
+ }
+ qq.extend(options, o);
+ registerPasteHandler();
+ qq.extend(this, {
+ reset: function() {
+ unregisterPasteHandler();
+ }
+ });
+ };
+ qq.FormSupport = function(options, startUpload, log) {
+ "use strict";
+ var self = this, interceptSubmit = options.interceptSubmit, formEl = options.element, autoUpload = options.autoUpload;
+ qq.extend(this, {
+ newEndpoint: null,
+ newAutoUpload: autoUpload,
+ attachedToForm: false,
+ getFormInputsAsObject: function() {
+ if (formEl == null) {
+ return null;
+ }
+ return self._form2Obj(formEl);
+ }
+ });
+ function determineNewEndpoint(formEl) {
+ if (formEl.getAttribute("action")) {
+ self.newEndpoint = formEl.getAttribute("action");
+ }
+ }
+ function validateForm(formEl, nativeSubmit) {
+ if (formEl.checkValidity && !formEl.checkValidity()) {
+ log("Form did not pass validation checks - will not upload.", "error");
+ nativeSubmit();
+ } else {
+ return true;
+ }
+ }
+ function maybeUploadOnSubmit(formEl) {
+ var nativeSubmit = formEl.submit;
+ qq(formEl).attach("submit", function(event) {
+ event = event || window.event;
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
+ validateForm(formEl, nativeSubmit) && startUpload();
+ });
+ formEl.submit = function() {
+ validateForm(formEl, nativeSubmit) && startUpload();
+ };
+ }
+ function determineFormEl(formEl) {
+ if (formEl) {
+ if (qq.isString(formEl)) {
+ formEl = document.getElementById(formEl);
+ }
+ if (formEl) {
+ log("Attaching to form element.");
+ determineNewEndpoint(formEl);
+ interceptSubmit && maybeUploadOnSubmit(formEl);
+ }
+ }
+ return formEl;
+ }
+ formEl = determineFormEl(formEl);
+ this.attachedToForm = !!formEl;
+ };
+ qq.extend(qq.FormSupport.prototype, {
+ _form2Obj: function(form) {
+ "use strict";
+ var obj = {}, notIrrelevantType = function(type) {
+ var irrelevantTypes = [ "button", "image", "reset", "submit" ];
+ return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;
+ }, radioOrCheckbox = function(type) {
+ return qq.indexOf([ "checkbox", "radio" ], type.toLowerCase()) >= 0;
+ }, ignoreValue = function(el) {
+ if (radioOrCheckbox(el.type) && !el.checked) {
+ return true;
+ }
+ return el.disabled && el.type.toLowerCase() !== "hidden";
+ }, selectValue = function(select) {
+ var value = null;
+ qq.each(qq(select).children(), function(idx, child) {
+ if (child.tagName.toLowerCase() === "option" && child.selected) {
+ value = child.value;
+ return false;
+ }
+ });
+ return value;
+ };
+ qq.each(form.elements, function(idx, el) {
+ if ((qq.isInput(el, true) || el.tagName.toLowerCase() === "textarea") && notIrrelevantType(el.type) && !ignoreValue(el)) {
+ obj[el.name] = el.value;
+ } else if (el.tagName.toLowerCase() === "select" && !ignoreValue(el)) {
+ var value = selectValue(el);
+ if (value !== null) {
+ obj[el.name] = value;
+ }
+ }
+ });
+ return obj;
+ }
+ });
+ qq.traditional = qq.traditional || {};
+ qq.traditional.FormUploadHandler = function(options, proxy) {
+ "use strict";
+ var handler = this, getName = proxy.getName, getUuid = proxy.getUuid, log = proxy.log;
+ function getIframeContentJson(id, iframe) {
+ var response, doc, innerHtml;
+ try {
+ doc = iframe.contentDocument || iframe.contentWindow.document;
+ innerHtml = doc.body.innerHTML;
+ log("converting iframe's innerHTML to JSON");
+ log("innerHTML = " + innerHtml);
+ if (innerHtml && innerHtml.match(/^= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\" \"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq*/\n/**\n * Upload handler used that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to\n * a generic server.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.traditional = qq.traditional || {};\nqq.traditional.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log;\n\n /**\n * Returns json object received by iframe from server.\n */\n function getIframeContentJson(id, iframe) {\n /*jshint evil: true*/\n\n var response, doc, innerHtml;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n log(\"converting iframe's innerHTML to JSON\");\n log(\"innerHTML = \" + innerHtml);\n //plain text response may be wrapped in tag\n if (innerHtml && innerHtml.match(/^=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),o=e.split(",")[0].split(":")[1].split(";")[0],t=new ArrayBuffer(n.length),i=new Uint8Array(t),qq.each(n,function(e,t){i[e]=t.charCodeAt(0)}),r(t,o)},qq.log=function(e,t){window.console&&(t&&"info"!==t?window.console[t]?window.console[t](e):window.console.log("<"+t+"> "+e):window.console.log(e))},qq.isObject=function(e){return e&&!e.nodeType&&"[object Object]"===Object.prototype.toString.call(e)},qq.isFunction=function(e){return"function"==typeof e},qq.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)||e&&window.ArrayBuffer&&e.buffer&&e.buffer.constructor===ArrayBuffer},qq.isItemList=function(e){return"[object DataTransferItemList]"===Object.prototype.toString.call(e)},qq.isNodeList=function(e){return"[object NodeList]"===Object.prototype.toString.call(e)||e.item&&e.namedItem},qq.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},qq.trimStr=function(e){return String.prototype.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},qq.format=function(e){var t=Array.prototype.slice.call(arguments,1),n=e,i=n.indexOf("{}");return qq.each(t,function(e,t){var o=n.substring(0,i),r=n.substring(i+2);if(n=o+t+r,i=n.indexOf("{}",i+t.length),i<0)return!1}),n},qq.isFile=function(e){return window.File&&"[object File]"===Object.prototype.toString.call(e)},qq.isFileList=function(e){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(e)},qq.isFileOrInput=function(e){return qq.isFile(e)||qq.isInput(e)},qq.isInput=function(e,t){var n=function(e){var n=e.toLowerCase();return t?"file"!==n:"file"===n};return!!(window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(e)&&e.type&&n(e.type))||!!(e.tagName&&"input"===e.tagName.toLowerCase()&&e.type&&n(e.type))},qq.isBlob=function(e){if(window.Blob&&"[object Blob]"===Object.prototype.toString.call(e))return!0},qq.isXhrUploadSupported=function(){var e=document.createElement("input");return e.type="file",void 0!==e.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&"undefined"!=typeof qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(e){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(e){return e.items&&e.items.length>0&&e.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(e,t,n){var i=e.slice||e.mozSlice||e.webkitSlice;return i.call(e,t,n)},qq.arrayBufferToHex=function(e){var t="",n=new Uint8Array(e);return qq.each(n,function(e,n){var i=n.toString(16);i.length<2&&(i="0"+i),t+=i}),t},qq.readBlobToHex=function(e,t,n){var i=qq.sliceBlob(e,t,t+n),o=new FileReader,r=new qq.Promise;return o.onload=function(){r.success(qq.arrayBufferToHex(o.result))},o.onerror=r.failure,o.readAsArrayBuffer(i),r},qq.extend=function(e,t,n){return qq.each(t,function(t,i){n&&qq.isObject(i)?(void 0===e[t]&&(e[t]={}),qq.extend(e[t],i,!0)):e[t]=i}),e},qq.override=function(e,t){var n={},i=t(n);return qq.each(i,function(t,i){void 0!==e[t]&&(n[t]=e[t]),e[t]=i}),e},qq.indexOf=function(e,t,n){if(e.indexOf)return e.indexOf(t,n);n=n||0;var i=e.length;for(n<0&&(n+=i);n=0},qq.safari=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Apple")!==-1},qq.chrome=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Google")!==-1},qq.opera=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Opera")!==-1},qq.firefox=function(){return!qq.edge()&&!qq.ie11()&&navigator.userAgent.indexOf("Mozilla")!==-1&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return navigator.userAgent.toLowerCase().indexOf("android")!==-1},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 6_")!==-1},qq.ios7=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 7_")!==-1},qq.ios8=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_")!==-1},qq.ios800=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_0 ")!==-1},qq.ios=function(){return navigator.userAgent.indexOf("iPad")!==-1||navigator.userAgent.indexOf("iPod")!==-1||navigator.userAgent.indexOf("iPhone")!==-1},qq.iosChrome=function(){return qq.ios()&&navigator.userAgent.indexOf("CriOS")!==-1},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&navigator.userAgent.indexOf("Safari")!==-1},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},qq.toElement=function(){var e=document.createElement("div");return function(t){e.innerHTML=t;var n=e.firstChild;return e.removeChild(n),n}}(),qq.each=function(e,t){var n,i;if(e)if(window.Storage&&e.constructor===window.Storage)for(n=0;n0)return e.substr(t,e.length-t)},qq.getFilename=function(e){return qq.isInput(e)?e.value.replace(/.*(\/|\\)/,""):qq.isFile(e)&&null!==e.fileName&&void 0!==e.fileName?e.fileName:e.name},qq.DisposeSupport=function(){var e=[];return{dispose:function(){var t;do t=e.shift(),t&&t();while(t)},attach:function(){var e=arguments;this.addDisposer(qq(e[0]).attach.apply(this,Array.prototype.slice.call(arguments,1)))},addDisposer:function(t){e.push(t)}}}}(),function(){"use strict";"function"==typeof define&&define.amd?define(function(){return qq}):"undefined"!=typeof module&&module.exports?module.exports=qq:global.qq=qq}(),function(){"use strict";qq.Error=function(e){this.message="[Fine Uploader "+qq.version+"] "+e},qq.Error.prototype=new Error}(),qq.version="5.13.0",qq.supportedFeatures=function(){"use strict";function e(){var e,t=!0;try{e=document.createElement("input"),e.type="file",qq(e).hide(),e.disabled&&(t=!1)}catch(e){t=!1}return t}function t(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/)}function n(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/)}function i(){if(window.XMLHttpRequest){var e=qq.createXhrInstance();return void 0!==e.withCredentials}return!1}function o(){return void 0!==window.XDomainRequest}function r(){return!!i()||o()}function a(){return void 0!==document.createElement("input").webkitdirectory}function s(){try{return!!window.localStorage&&qq.isFunction(window.localStorage.setItem)}catch(e){return!1}}function u(){var e=document.createElement("span");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&!qq.android()&&!qq.ios()}var l,c,d,p,f,q,h,m,g,_,b,v,S,w,y;return l=e(),p=l&&qq.isXhrUploadSupported(),c=p&&!qq.androidStock(),d=p&&u(),f=d&&t(),q=p&&qq.isFileChunkingSupported(),h=p&&q&&s(),m=p&&n(),g=l&&(void 0!==window.postMessage||p),b=i(),_=o(),v=r(),S=a(),w=p&&void 0!==window.FileReader,y=function(){return!!p&&(!qq.androidStock()&&!qq.iosChrome())}(),{ajaxUploading:p,blobUploading:c,canDetermineSize:p,chunking:q,deleteFileCors:v,deleteFileCorsXdr:_,deleteFileCorsXhr:b,dialogElement:!!window.HTMLDialogElement,fileDrop:d,folderDrop:f,folderSelection:S,imagePreviews:w,imageValidation:w,itemSizeValidation:p,pause:q,progressBar:y,resume:h,scaling:w&&c,tiffPreviews:qq.safari(),unlimitedScaledImageSize:!qq.ios(),uploading:l,uploadCors:g,uploadCustomHeaders:p,uploadNonMultipart:p,uploadViaPaste:m}}(),qq.isGenericPromise=function(e){"use strict";return!!(e&&e.then&&qq.isFunction(e.then))},qq.Promise=function(){"use strict";var e,t,n=[],i=[],o=[],r=0;qq.extend(this,{then:function(o,a){return 0===r?(o&&n.push(o),a&&i.push(a)):r===-1?a&&a.apply(null,t):o&&o.apply(null,e),this},done:function(n){return 0===r?o.push(n):n.apply(null,void 0===t?e:t),this},success:function(){return r=1,e=arguments,n.length&&qq.each(n,function(t,n){n.apply(null,e)}),o.length&&qq.each(o,function(t,n){n.apply(null,e)}),this},failure:function(){return r=-1,t=arguments,i.length&&qq.each(i,function(e,n){n.apply(null,t)}),o.length&&qq.each(o,function(e,n){n.apply(null,t)}),this}})},qq.BlobProxy=function(e,t){"use strict";qq.extend(this,{referenceBlob:e,create:function(){return t(e)}})},qq.UploadButton=function(e){"use strict";function t(){var e=document.createElement("input");return e.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME,i),e.setAttribute("title",a.title),o.setMultiple(a.multiple,e),a.folders&&qq.supportedFeatures.folderSelection&&e.setAttribute("webkitdirectory",""),a.acceptFiles&&e.setAttribute("accept",a.acceptFiles),e.setAttribute("type","file"),e.setAttribute("name",a.name),qq(e).css({position:"absolute",right:0,top:0,fontFamily:"Arial",fontSize:qq.ie()&&!qq.ie8()?"3500px":"118px",margin:0,padding:0,cursor:"pointer",opacity:0}),!qq.ie7()&&qq(e).css({height:"100%"}),a.element.appendChild(e),r.attach(e,"change",function(){a.onChange(e)}),r.attach(e,"mouseover",function(){qq(a.element).addClass(a.hoverClass)}),r.attach(e,"mouseout",function(){qq(a.element).removeClass(a.hoverClass)}),r.attach(e,"focus",function(){qq(a.element).addClass(a.focusClass)}),r.attach(e,"blur",function(){qq(a.element).removeClass(a.focusClass)}),e}var n,i,o=this,r=new qq.DisposeSupport,a={acceptFiles:null,element:null,focusClass:"qq-upload-button-focus",folders:!1,hoverClass:"qq-upload-button-hover",ios8BrowserCrashWorkaround:!1,multiple:!1,name:"qqfile",onChange:function(e){},title:null};qq.extend(a,e),i=qq.getUniqueId(),qq(a.element).css({position:"relative",overflow:"hidden",direction:"ltr"}),qq.extend(this,{getInput:function(){return n},getButtonId:function(){return i},setMultiple:function(e,t){var n=t||this.getInput();a.ios8BrowserCrashWorkaround&&qq.ios8()&&(qq.iosChrome()||qq.iosSafariWebView())?n.setAttribute("multiple",""):e?n.setAttribute("multiple",""):n.removeAttribute("multiple")},setAcceptFiles:function(e){e!==a.acceptFiles&&n.setAttribute("accept",e)},reset:function(){n.parentNode&&qq(n).remove(),qq(a.element).removeClass(a.focusClass),n=null,n=t()}}),n=t()},qq.UploadButton.BUTTON_ID_ATTR_NAME="qq-button-id",qq.UploadData=function(e){"use strict";function t(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[n])}),t}return o[e]}function n(e){if(qq.isArray(e)){var t=[];return qq.each(e,function(e,n){t.push(o[r[n]])}),t}return o[r[e]]}function i(e){var t=[],n=[].concat(e);return qq.each(n,function(e,n){var i=a[n];void 0!==i&&qq.each(i,function(e,n){t.push(o[n])})}),t}var o=[],r={},a={},s={},u={};qq.extend(this,{addFile:function(t){var n=t.status||qq.status.SUBMITTING,i=o.push({name:t.name,originalName:t.name,uuid:t.uuid,size:null==t.size?-1:t.size,status:n})-1;return t.batchId&&(o[i].batchId=t.batchId,void 0===u[t.batchId]&&(u[t.batchId]=[]),u[t.batchId].push(i)),t.proxyGroupId&&(o[i].proxyGroupId=t.proxyGroupId,void 0===s[t.proxyGroupId]&&(s[t.proxyGroupId]=[]),s[t.proxyGroupId].push(i)),o[i].id=i,r[t.uuid]=i,void 0===a[n]&&(a[n]=[]),a[n].push(i),e.onStatusChange(i,null,n),i},retrieve:function(e){return qq.isObject(e)&&o.length?void 0!==e.id?t(e.id):void 0!==e.uuid?n(e.uuid):e.status?i(e.status):void 0:qq.extend([],o,!0)},reset:function(){o=[],r={},a={},u={}},setStatus:function(t,n){var i=o[t].status,r=qq.indexOf(a[i],t);a[i].splice(r,1),o[t].status=n,void 0===a[n]&&(a[n]=[]),a[n].push(t),e.onStatusChange(t,i,n)},uuidChanged:function(e,t){var n=o[e].uuid;o[e].uuid=t,r[t]=e,delete r[n]},updateName:function(e,t){o[e].name=t},updateSize:function(e,t){o[e].size=t},setParentId:function(e,t){o[e].parentId=t},getIdsInProxyGroup:function(e){var t=o[e].proxyGroupId;return t?s[t]:[]},getIdsInBatch:function(e){var t=o[e].batchId;return u[t]}})},qq.status={SUBMITTING:"submitting",SUBMITTED:"submitted",REJECTED:"rejected",QUEUED:"queued",CANCELED:"canceled",PAUSED:"paused",UPLOADING:"uploading",UPLOAD_RETRYING:"retrying upload",UPLOAD_SUCCESSFUL:"upload successful",UPLOAD_FAILED:"upload failed",DELETE_FAILED:"delete failed",DELETING:"deleting",DELETED:"deleted"},function(){"use strict";qq.basePublicApi={addBlobs:function(e,t,n){this.addFiles(e,t,n)},addInitialFiles:function(e){var t=this;qq.each(e,function(e,n){t._addCannedFile(n)})},addFiles:function(e,t,n){this._maybeHandleIos8SafariWorkaround();var i=0===this._storedIds.length?qq.getUniqueId():this._currentBatchId,o=qq.bind(function(e){this._handleNewFile({blob:e,name:this._options.blobs.defaultName},i,d)},this),r=qq.bind(function(e){this._handleNewFile(e,i,d)},this),a=qq.bind(function(e){var t=qq.canvasToBlob(e);this._handleNewFile({blob:t,name:this._options.blobs.defaultName+".png"},i,d)},this),s=qq.bind(function(e){var t=e.quality&&e.quality/100,n=qq.canvasToBlob(e.canvas,e.type,t);this._handleNewFile({blob:n,name:e.name},i,d)},this),u=qq.bind(function(e){if(qq.isInput(e)&&qq.supportedFeatures.ajaxUploading){var t=Array.prototype.slice.call(e.files),n=this;qq.each(t,function(e,t){n._handleNewFile(t,i,d)})}else this._handleNewFile(e,i,d)},this),l=function(){qq.isFileList(e)&&(e=Array.prototype.slice.call(e)),e=[].concat(e)},c=this,d=[];this._currentBatchId=i,e&&(l(),qq.each(e,function(e,t){qq.isFileOrInput(t)?u(t):qq.isBlob(t)?o(t):qq.isObject(t)?t.blob&&t.name?r(t):t.canvas&&t.name&&s(t):t.tagName&&"canvas"===t.tagName.toLowerCase()?a(t):c.log(t+" is not a valid file container! Ignoring!","warn")}),this.log("Received "+d.length+" files."),this._prepareItemsForUpload(d,t,n))},cancel:function(e){this._handler.cancel(e)},cancelAll:function(){var e=[],t=this;qq.extend(e,this._storedIds),qq.each(e,function(e,n){t.cancel(n)}),this._handler.cancelAll()},clearStoredFiles:function(){this._storedIds=[]},continueUpload:function(e){var t=this._uploadData.retrieve({id:e});return!(!qq.supportedFeatures.pause||!this._options.chunking.enabled)&&(t.status===qq.status.PAUSED?(this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.",e,this.getName(e))),this._uploadFile(e),!0):(this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.",e,this.getName(e)),"error"),!1))},deleteFile:function(e){return this._onSubmitDelete(e)},doesExist:function(e){return this._handler.isValid(e)},drawThumbnail:function(e,t,n,i,o){var r,a,s=new qq.Promise;return this._imageGenerator?(r=this._thumbnailUrls[e],a={customResizeFunction:o,maxSize:n>0?n:null,scale:n>0},!i&&qq.supportedFeatures.imagePreviews&&(r=this.getFile(e)),null==r?s.failure({container:t,error:"File or URL not found."}):this._imageGenerator.generate(r,t,a).then(function(e){s.success(e)},function(e,t){s.failure({container:e,error:t||"Problem generating thumbnail"})})):s.failure({container:t,error:"Missing image generator module"}),s},getButton:function(e){return this._getButton(this._buttonIdsForFileIds[e])},getEndpoint:function(e){return this._endpointStore.get(e)},getFile:function(e){return this._handler.getFile(e)||null},getInProgress:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED]}).length},getName:function(e){return this._uploadData.retrieve({id:e}).name},getParentId:function(e){var t=this.getUploads({id:e}),n=null;return t&&void 0!==t.parentId&&(n=t.parentId),n},getResumableFilesData:function(){return this._handler.getResumableFilesData()},getSize:function(e){return this._uploadData.retrieve({id:e}).size},getNetUploads:function(){return this._netUploaded},getRemainingAllowedItems:function(){var e=this._currentItemLimit;return e>0?e-this._netUploadedOrQueued:null},getUploads:function(e){return this._uploadData.retrieve(e)},getUuid:function(e){return this._uploadData.retrieve({id:e}).uuid},log:function(e,t){!this._options.debug||t&&"info"!==t?t&&"info"!==t&&qq.log("[Fine Uploader "+qq.version+"] "+e,t):qq.log("[Fine Uploader "+qq.version+"] "+e)},pauseUpload:function(e){var t=this._uploadData.retrieve({id:e});if(!qq.supportedFeatures.pause||!this._options.chunking.enabled)return!1;if(qq.indexOf([qq.status.UPLOADING,qq.status.UPLOAD_RETRYING],t.status)>=0){if(this._handler.pause(e))return this._uploadData.setStatus(e,qq.status.PAUSED),!0;this.log(qq.format("Unable to pause file ID {} ({}).",e,this.getName(e)),"error")}else this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.",e,this.getName(e)),"error");return!1},reset:function(){this.log("Resetting uploader..."),this._handler.reset(),this._storedIds=[],this._autoRetries=[],this._retryTimeouts=[],this._preventRetries=[],this._thumbnailUrls=[],qq.each(this._buttons,function(e,t){t.reset()}),this._paramsStore.reset(),this._endpointStore.reset(),this._netUploadedOrQueued=0,this._netUploaded=0,this._uploadData.reset(),this._buttonIdsForFileIds=[],this._pasteHandler&&this._pasteHandler.reset(),this._options.session.refreshOnReset&&this._refreshSessionData(),this._succeededSinceLastAllComplete=[],this._failedSinceLastAllComplete=[],this._totalProgress&&this._totalProgress.reset()},retry:function(e){return this._manualRetry(e)},scaleImage:function(e,t){var n=this;return qq.Scaler.prototype.scaleImage(e,t,{log:qq.bind(n.log,n),getFile:qq.bind(n.getFile,n),uploadData:n._uploadData})},setCustomHeaders:function(e,t){this._customHeadersStore.set(e,t)},setDeleteFileCustomHeaders:function(e,t){this._deleteFileCustomHeadersStore.set(e,t)},setDeleteFileEndpoint:function(e,t){this._deleteFileEndpointStore.set(e,t)},setDeleteFileParams:function(e,t){this._deleteFileParamsStore.set(e,t)},setEndpoint:function(e,t){this._endpointStore.set(e,t)},setForm:function(e){this._updateFormSupportAndParams(e)},setItemLimit:function(e){this._currentItemLimit=e},setName:function(e,t){this._uploadData.updateName(e,t)},setParams:function(e,t){this._paramsStore.set(e,t)},setUuid:function(e,t){return this._uploadData.uuidChanged(e,t)},uploadStoredFiles:function(){0===this._storedIds.length?this._itemError("noFilesError"):this._uploadStoredFiles()}},qq.basePrivateApi={_addCannedFile:function(e){var t=this._uploadData.addFile({uuid:e.uuid,name:e.name,size:e.size,status:qq.status.UPLOAD_SUCCESSFUL});return e.deleteFileEndpoint&&this.setDeleteFileEndpoint(e.deleteFileEndpoint,t),e.deleteFileParams&&this.setDeleteFileParams(e.deleteFileParams,t),e.thumbnailUrl&&(this._thumbnailUrls[t]=e.thumbnailUrl),this._netUploaded++,this._netUploadedOrQueued++,t},_annotateWithButtonId:function(e,t){qq.isFile(e)&&(e.qqButtonId=this._getButtonId(t))},_batchError:function(e){this._options.callbacks.onError(null,null,e,void 0)},_createDeleteHandler:function(){var e=this;return new qq.DeleteFileAjaxRequester({method:this._options.deleteFile.method.toUpperCase(),maxConnections:this._options.maxConnections,uuidParamName:this._options.request.uuidName,customHeaders:this._deleteFileCustomHeadersStore,paramsStore:this._deleteFileParamsStore,endpointStore:this._deleteFileEndpointStore,cors:this._options.cors,log:qq.bind(e.log,e),onDelete:function(t){e._onDelete(t),e._options.callbacks.onDelete(t)},onDeleteComplete:function(t,n,i){e._onDeleteComplete(t,n,i),e._options.callbacks.onDeleteComplete(t,n,i)}})},_createPasteHandler:function(){var e=this;return new qq.PasteSupport({targetElement:this._options.paste.targetElement,callbacks:{log:qq.bind(e.log,e),pasteReceived:function(t){e._handleCheckedCallback({name:"onPasteReceived",callback:qq.bind(e._options.callbacks.onPasteReceived,e,t),onSuccess:qq.bind(e._handlePasteSuccess,e,t),identifier:"pasted image"})}}})},_createStore:function(e,t){var n={},i=e,o={},r=t,a=function(e){return qq.isObject(e)?qq.extend({},e):e},s=function(){return qq.isFunction(r)?r():r},u=function(e,t){r&&qq.isObject(t)&&qq.extend(t,s()),o[e]&&qq.extend(t,o[e])};return{set:function(e,t){null==t?(n={},i=a(e)):n[t]=a(e)},get:function(e){var t;return t=null!=e&&n[e]?n[e]:a(i),u(e,t),a(t)},addReadOnly:function(e,t){qq.isObject(n)&&(null===e?qq.isFunction(t)?r=t:(r=r||{},qq.extend(r,t)):(o[e]=o[e]||{},qq.extend(o[e],t)))},remove:function(e){return delete n[e]},reset:function(){n={},o={},i=e}}},_createUploadDataTracker:function(){var e=this;return new qq.UploadData({getName:function(t){return e.getName(t)},getUuid:function(t){return e.getUuid(t)},getSize:function(t){return e.getSize(t)},onStatusChange:function(t,n,i){e._onUploadStatusChange(t,n,i),e._options.callbacks.onStatusChange(t,n,i),e._maybeAllComplete(t,i),e._totalProgress&&setTimeout(function(){e._totalProgress.onStatusChange(t,n,i)},0)}})},_createUploadButton:function(e){function t(){return!!qq.supportedFeatures.ajaxUploading&&(!(i._options.workarounds.iosEmptyVideos&&qq.ios()&&!qq.ios6()&&i._isAllowedExtension(r,".mov"))&&(void 0===e.multiple?i._options.multiple:e.multiple))}var n,i=this,o=e.accept||this._options.validation.acceptFiles,r=e.allowedExtensions||this._options.validation.allowedExtensions;return n=new qq.UploadButton({acceptFiles:o,element:e.element,focusClass:this._options.classes.buttonFocus,folders:e.folders,hoverClass:this._options.classes.buttonHover,ios8BrowserCrashWorkaround:this._options.workarounds.ios8BrowserCrash,multiple:t(),name:this._options.request.inputName,onChange:function(e){i._onInputChange(e)},title:null==e.title?this._options.text.fileInputTitle:e.title}),this._disposeSupport.addDisposer(function(){n.dispose()}),i._buttons.push(n),n},_createUploadHandler:function(e,t){var n=this,i={},o={debug:this._options.debug,maxConnections:this._options.maxConnections,cors:this._options.cors,paramsStore:this._paramsStore,endpointStore:this._endpointStore,chunking:this._options.chunking,resume:this._options.resume,blobs:this._options.blobs,log:qq.bind(n.log,n),preventRetryParam:this._options.retry.preventRetryResponseProperty,onProgress:function(e,t,o,r){o<0||r<0||(i[e]?i[e].loaded===o&&i[e].total===r||(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)):(n._onProgress(e,t,o,r),n._options.callbacks.onProgress(e,t,o,r)),i[e]={loaded:o,total:r})},onComplete:function(e,t,o,r){delete i[e];var a,s=n.getUploads({id:e}).status;s!==qq.status.UPLOAD_SUCCESSFUL&&s!==qq.status.UPLOAD_FAILED&&(a=n._onComplete(e,t,o,r),a instanceof qq.Promise?a.done(function(){n._options.callbacks.onComplete(e,t,o,r)}):n._options.callbacks.onComplete(e,t,o,r))},onCancel:function(e,t,i){var o=new qq.Promise;return n._handleCheckedCallback({name:"onCancel",callback:qq.bind(n._options.callbacks.onCancel,n,e,t),onFailure:o.failure,onSuccess:function(){i.then(function(){n._onCancel(e,t)}),o.success()},identifier:e}),o},onUploadPrep:qq.bind(this._onUploadPrep,this),onUpload:function(e,t){n._onUpload(e,t),n._options.callbacks.onUpload(e,t)},onUploadChunk:function(e,t,i){n._onUploadChunk(e,i),n._options.callbacks.onUploadChunk(e,t,i)},onUploadChunkSuccess:function(e,t,i,o){n._options.callbacks.onUploadChunkSuccess.apply(n,arguments)},onResume:function(e,t,i){return n._options.callbacks.onResume(e,t,i)},onAutoRetry:function(e,t,i,o){return n._onAutoRetry.apply(n,arguments)},onUuidChanged:function(e,t){n.log("Server requested UUID change from '"+n.getUuid(e)+"' to '"+t+"'"),n.setUuid(e,t)},getName:qq.bind(n.getName,n),getUuid:qq.bind(n.getUuid,n),getSize:qq.bind(n.getSize,n),setSize:qq.bind(n._setSize,n),getDataByUuid:function(e){return n.getUploads({uuid:e})},isQueued:function(e){var t=n.getUploads({id:e}).status;return t===qq.status.QUEUED||t===qq.status.SUBMITTED||t===qq.status.UPLOAD_RETRYING||t===qq.status.PAUSED},getIdsInProxyGroup:n._uploadData.getIdsInProxyGroup,getIdsInBatch:n._uploadData.getIdsInBatch};return qq.each(this._options.request,function(e,t){o[e]=t}),o.customHeaders=this._customHeadersStore,e&&qq.each(e,function(e,t){o[e]=t}),new qq.UploadHandlerController(o,t)},_fileOrBlobRejected:function(e){this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.REJECTED)},_formatSize:function(e){if(0===e)return e+this._options.text.sizeSymbols[0];var t=-1;do e/=1e3,t++;while(e>999);return Math.max(e,.1).toFixed(1)+this._options.text.sizeSymbols[t]},_generateExtraButtonSpecs:function(){var e=this;this._extraButtonSpecs={},qq.each(this._options.extraButtons,function(t,n){var i=n.multiple,o=qq.extend({},e._options.validation,!0),r=qq.extend({},n);void 0===i&&(i=e._options.multiple),r.validation&&qq.extend(o,n.validation,!0),qq.extend(r,{multiple:i,validation:o},!0),e._initExtraButton(r)})},_getButton:function(e){var t=this._extraButtonSpecs[e];return t?t.element:e===this._defaultButtonId?this._options.button:void 0},_getButtonId:function(e){var t,n,i=e;if(i instanceof qq.BlobProxy&&(i=i.referenceBlob),i&&!qq.isBlob(i)){if(qq.isFile(i))return i.qqButtonId;if("input"===i.tagName.toLowerCase()&&"file"===i.type.toLowerCase())return i.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);if(t=i.getElementsByTagName("input"),qq.each(t,function(e,t){if("file"===t.getAttribute("type"))return n=t,!1}),n)return n.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME)}},_getNotFinished:function(){return this._uploadData.retrieve({status:[qq.status.UPLOADING,qq.status.UPLOAD_RETRYING,qq.status.QUEUED,qq.status.SUBMITTING,qq.status.SUBMITTED,qq.status.PAUSED]}).length},_getValidationBase:function(e){var t=this._extraButtonSpecs[e];return t?t.validation:this._options.validation},_getValidationDescriptor:function(e){return e.file instanceof qq.BlobProxy?{name:qq.getFilename(e.file.referenceBlob),size:e.file.referenceBlob.size}:{name:this.getUploads({id:e.id}).name,size:this.getUploads({id:e.id}).size}},_getValidationDescriptors:function(e){var t=this,n=[];return qq.each(e,function(e,i){n.push(t._getValidationDescriptor(i))}),n},_handleCameraAccess:function(){if(this._options.camera.ios&&qq.ios()){var e="image/*;capture=camera",t=this._options.camera.button,n=t?this._getButtonId(t):this._defaultButtonId,i=this._options;n&&n!==this._defaultButtonId&&(i=this._extraButtonSpecs[n]),i.multiple=!1,null===i.validation.acceptFiles?i.validation.acceptFiles=e:i.validation.acceptFiles+=","+e,qq.each(this._buttons,function(e,t){if(t.getButtonId()===n)return t.setMultiple(i.multiple),t.setAcceptFiles(i.acceptFiles),!1})}},_handleCheckedCallback:function(e){var t=this,n=e.callback();return qq.isGenericPromise(n)?(this.log(e.name+" - waiting for "+e.name+" promise to be fulfilled for "+e.identifier),n.then(function(n){t.log(e.name+" promise success for "+e.identifier),e.onSuccess(n)},function(){e.onFailure?(t.log(e.name+" promise failure for "+e.identifier),e.onFailure()):t.log(e.name+" promise failure for "+e.identifier)})):(n!==!1?e.onSuccess(n):e.onFailure?(this.log(e.name+" - return value was 'false' for "+e.identifier+". Invoking failure callback."),e.onFailure()):this.log(e.name+" - return value was 'false' for "+e.identifier+". Will not proceed."),n)},_handleNewFile:function(e,t,n){var i=this,o=qq.getUniqueId(),r=-1,a=qq.getFilename(e),s=e.blob||e,u=this._customNewFileHandler?this._customNewFileHandler:qq.bind(i._handleNewFileGeneric,i);!qq.isInput(s)&&s.size>=0&&(r=s.size),u(s,a,o,r,n,t,this._options.request.uuidName,{uploadData:i._uploadData,paramsStore:i._paramsStore,addFileToHandler:function(e,t){i._handler.add(e,t),i._netUploadedOrQueued++,i._trackButton(e);
+}})},_handleNewFileGeneric:function(e,t,n,i,o,r){var a=this._uploadData.addFile({uuid:n,name:t,size:i,batchId:r});this._handler.add(a,e),this._trackButton(a),this._netUploadedOrQueued++,o.push({id:a,file:e})},_handlePasteSuccess:function(e,t){var n=e.type.split("/")[1],i=t;null==i&&(i=this._options.paste.defaultName),i+="."+n,this.addFiles({name:i,blob:e})},_initExtraButton:function(e){var t=this._createUploadButton({accept:e.validation.acceptFiles,allowedExtensions:e.validation.allowedExtensions,element:e.element,folders:e.folders,multiple:e.multiple,title:e.fileInputTitle});this._extraButtonSpecs[t.getButtonId()]=e},_initFormSupportAndParams:function(){this._formSupport=qq.FormSupport&&new qq.FormSupport(this._options.form,qq.bind(this.uploadStoredFiles,this),qq.bind(this.log,this)),this._formSupport&&this._formSupport.attachedToForm?(this._paramsStore=this._createStore(this._options.request.params,this._formSupport.getFormInputsAsObject),this._options.autoUpload=this._formSupport.newAutoUpload,this._formSupport.newEndpoint&&(this._options.request.endpoint=this._formSupport.newEndpoint)):this._paramsStore=this._createStore(this._options.request.params)},_isDeletePossible:function(){return!(!qq.DeleteFileAjaxRequester||!this._options.deleteFile.enabled)&&(!this._options.cors.expected||(!!qq.supportedFeatures.deleteFileCorsXhr||!(!qq.supportedFeatures.deleteFileCorsXdr||!this._options.cors.allowXdr)))},_isAllowedExtension:function(e,t){var n=!1;return!e.length||(qq.each(e,function(e,i){if(qq.isString(i)){var o=new RegExp("\\."+i+"$","i");if(null!=t.match(o))return n=!0,!1}}),n)},_itemError:function(e,t,n){function i(e,t){a=a.replace(e,t)}var o,r,a=this._options.messages[e],s=[],u=[].concat(t),l=u[0],c=this._getButtonId(n),d=this._getValidationBase(c);return qq.each(d.allowedExtensions,function(e,t){qq.isString(t)&&s.push(t)}),o=s.join(", ").toLowerCase(),i("{file}",this._options.formatFileName(l)),i("{extensions}",o),i("{sizeLimit}",this._formatSize(d.sizeLimit)),i("{minSizeLimit}",this._formatSize(d.minSizeLimit)),r=a.match(/(\{\w+\})/g),null!==r&&qq.each(r,function(e,t){i(t,u[e])}),this._options.callbacks.onError(null,l,a,void 0),a},_manualRetry:function(e,t){if(this._onBeforeManualRetry(e))return this._netUploadedOrQueued++,this._uploadData.setStatus(e,qq.status.UPLOAD_RETRYING),t?t(e):this._handler.retry(e),!0},_maybeAllComplete:function(e,t){var n=this,i=this._getNotFinished();t===qq.status.UPLOAD_SUCCESSFUL?this._succeededSinceLastAllComplete.push(e):t===qq.status.UPLOAD_FAILED&&this._failedSinceLastAllComplete.push(e),0===i&&(this._succeededSinceLastAllComplete.length||this._failedSinceLastAllComplete.length)&&setTimeout(function(){n._onAllComplete(n._succeededSinceLastAllComplete,n._failedSinceLastAllComplete)},0)},_maybeHandleIos8SafariWorkaround:function(){var e=this;if(this._options.workarounds.ios8SafariUploads&&qq.ios800()&&qq.iosSafari())throw setTimeout(function(){window.alert(e._options.messages.unsupportedBrowserIos8Safari)},0),new qq.Error(this._options.messages.unsupportedBrowserIos8Safari)},_maybeParseAndSendUploadError:function(e,t,n,i){if(!n.success)if(i&&200!==i.status&&!n.error)this._options.callbacks.onError(e,t,"XHR returned response code "+i.status,i);else{var o=n.error?n.error:this._options.text.defaultResponseError;this._options.callbacks.onError(e,t,o,i)}},_maybeProcessNextItemAfterOnValidateCallback:function(e,t,n,i,o){var r=this;if(t.length>n)if(e||!this._options.validation.stopOnFirstInvalidFile)setTimeout(function(){var e=r._getValidationDescriptor(t[n]),a=r._getButtonId(t[n].file),s=r._getButton(a);r._handleCheckedCallback({name:"onValidate",callback:qq.bind(r._options.callbacks.onValidate,r,e,s),onSuccess:qq.bind(r._onValidateCallbackSuccess,r,t,n,i,o),onFailure:qq.bind(r._onValidateCallbackFailure,r,t,n,i,o),identifier:"Item '"+e.name+"', size: "+e.size})},0);else if(!e)for(;n0&&this._netUploadedOrQueued+1>n?(this._itemError("retryFailTooManyItems"),!1):(this.log("Retrying upload for '"+t+"' (id: "+e+")..."),!0))):(this.log("'"+e+"' is not a valid file ID","error"),!1)},_onCancel:function(e,t){this._netUploadedOrQueued--,clearTimeout(this._retryTimeouts[e]);var n=qq.indexOf(this._storedIds,e);!this._options.autoUpload&&n>=0&&this._storedIds.splice(n,1),this._uploadData.setStatus(e,qq.status.CANCELED)},_onComplete:function(e,t,n,i){return n.success?(n.thumbnailUrl&&(this._thumbnailUrls[e]=n.thumbnailUrl),this._netUploaded++,this._uploadData.setStatus(e,qq.status.UPLOAD_SUCCESSFUL)):(this._netUploadedOrQueued--,this._uploadData.setStatus(e,qq.status.UPLOAD_FAILED),n[this._options.retry.preventRetryResponseProperty]===!0&&(this._preventRetries[e]=!0)),this._maybeParseAndSendUploadError(e,t,n,i),!!n.success},_onDelete:function(e){this._uploadData.setStatus(e,qq.status.DELETING)},_onDeleteComplete:function(e,t,n){var i=this.getName(e);n?(this._uploadData.setStatus(e,qq.status.DELETE_FAILED),this.log("Delete request for '"+i+"' has failed.","error"),void 0===t.withCredentials?this._options.callbacks.onError(e,i,"Delete request failed",t):this._options.callbacks.onError(e,i,"Delete request failed with response code "+t.status,t)):(this._netUploadedOrQueued--,this._netUploaded--,this._handler.expunge(e),this._uploadData.setStatus(e,qq.status.DELETED),this.log("Delete request for '"+i+"' has succeeded."))},_onInputChange:function(e){var t;if(qq.supportedFeatures.ajaxUploading){for(t=0;t0&&this.addFiles(e);qq.each(this._buttons,function(e,t){t.reset()})},_onProgress:function(e,t,n,i){this._totalProgress&&this._totalProgress.onIndividualProgress(e,n,i)},_onSubmit:function(e,t){},_onSubmitCallbackSuccess:function(e,t){this._onSubmit.apply(this,arguments),this._uploadData.setStatus(e,qq.status.SUBMITTED),this._onSubmitted.apply(this,arguments),this._options.autoUpload?(this._options.callbacks.onSubmitted.apply(this,arguments),this._uploadFile(e)):(this._storeForLater(e),this._options.callbacks.onSubmitted.apply(this,arguments))},_onSubmitDelete:function(e,t,n){var i,o=this.getUuid(e);return t&&(i=qq.bind(t,this,e,o,n)),this._isDeletePossible()?(this._handleCheckedCallback({name:"onSubmitDelete",callback:qq.bind(this._options.callbacks.onSubmitDelete,this,e),onSuccess:i||qq.bind(this._deleteHandler.sendDelete,this,e,o,n),identifier:e}),!0):(this.log("Delete request ignored for ID "+e+", delete feature is disabled or request not possible due to CORS on a user agent that does not support pre-flighting.","warn"),!1)},_onSubmitted:function(e){},_onTotalProgress:function(e,t){this._options.callbacks.onTotalProgress(e,t)},_onUploadPrep:function(e){},_onUpload:function(e,t){this._uploadData.setStatus(e,qq.status.UPLOADING)},_onUploadChunk:function(e,t){},_onUploadStatusChange:function(e,t,n){n===qq.status.PAUSED&&clearTimeout(this._retryTimeouts[e])},_onValidateBatchCallbackFailure:function(e){var t=this;qq.each(e,function(e,n){t._fileOrBlobRejected(n.id)})},_onValidateBatchCallbackSuccess:function(e,t,n,i,o){var r,a=this._currentItemLimit,s=this._netUploadedOrQueued;0===a||s<=a?t.length>0?this._handleCheckedCallback({name:"onValidate",callback:qq.bind(this._options.callbacks.onValidate,this,e[0],o),onSuccess:qq.bind(this._onValidateCallbackSuccess,this,t,0,n,i),onFailure:qq.bind(this._onValidateCallbackFailure,this,t,0,n,i),identifier:"Item '"+t[0].file.name+"', size: "+t[0].file.size}):this._itemError("noFilesError"):(this._onValidateBatchCallbackFailure(t),r=this._options.messages.tooManyItemsError.replace(/\{netItems\}/g,s).replace(/\{itemLimit\}/g,a),this._batchError(r))},_onValidateCallbackFailure:function(e,t,n,i){var o=t+1;this._fileOrBlobRejected(e[t].id,e[t].file.name),this._maybeProcessNextItemAfterOnValidateCallback(!1,e,o,n,i)},_onValidateCallbackSuccess:function(e,t,n,i){var o=this,r=t+1,a=this._getValidationDescriptor(e[t]);this._validateFileOrBlobData(e[t],a).then(function(){o._upload(e[t].id,n,i),o._maybeProcessNextItemAfterOnValidateCallback(!0,e,r,n,i)},function(){o._maybeProcessNextItemAfterOnValidateCallback(!1,e,r,n,i)})},_prepareItemsForUpload:function(e,t,n){if(0===e.length)return void this._itemError("noFilesError");var i=this._getValidationDescriptors(e),o=this._getButtonId(e[0].file),r=this._getButton(o);this._handleCheckedCallback({name:"onValidateBatch",callback:qq.bind(this._options.callbacks.onValidateBatch,this,i,r),onSuccess:qq.bind(this._onValidateBatchCallbackSuccess,this,i,e,t,n,r),onFailure:qq.bind(this._onValidateBatchCallbackFailure,this,e),identifier:"batch validation"})},_preventLeaveInProgress:function(){var e=this;this._disposeSupport.attach(window,"beforeunload",function(t){if(e.getInProgress())return t=t||window.event,t.returnValue=e._options.messages.onLeave,e._options.messages.onLeave})},_refreshSessionData:function(){var e=this,t=this._options.session;qq.Session&&null!=this._options.session.endpoint&&(this._session||(qq.extend(t,{cors:this._options.cors}),t.log=qq.bind(this.log,this),t.addFileRecord=qq.bind(this._addCannedFile,this),this._session=new qq.Session(t)),setTimeout(function(){e._session.refresh().then(function(t,n){e._sessionRequestComplete(),e._options.callbacks.onSessionRequestComplete(t,!0,n)},function(t,n){e._options.callbacks.onSessionRequestComplete(t,!1,n)})},0))},_sessionRequestComplete:function(){},_setSize:function(e,t){this._uploadData.updateSize(e,t),this._totalProgress&&this._totalProgress.onNewSize(e)},_shouldAutoRetry:function(e,t,n){var i=this._uploadData.retrieve({id:e});return!!(!this._preventRetries[e]&&this._options.retry.enableAuto&&i.status!==qq.status.PAUSED&&(void 0===this._autoRetries[e]&&(this._autoRetries[e]=0),this._autoRetries[e]0&&s.sizeLimit&&r>s.sizeLimit?(this._itemError("sizeError",o,i),u.failure()):r>0&&r=0}function n(e){var t=!1;return qq.each(t,function(e,n){if(qq.indexOf(["Accept","Accept-Language","Content-Language","Content-Type"],n)<0)return t=!0,!1}),t}function i(e){return w.cors.expected&&void 0===e.withCredentials}function o(){var e;return(window.XMLHttpRequest||window.ActiveXObject)&&(e=qq.createXhrInstance(),void 0===e.withCredentials&&(e=new XDomainRequest,e.onload=function(){},e.onerror=function(){},e.ontimeout=function(){},e.onprogress=function(){})),e}function r(e,t){var n=S[e].xhr;return n||(n=t?t:w.cors.expected?o():qq.createXhrInstance(),S[e].xhr=n),n}function a(e){var t,n=qq.indexOf(v,e),i=w.maxConnections;delete S[e],v.splice(n,1),v.length>=i&&n=0?o.send(qq.obj2url(s,"")):s&&w.contentType&&w.contentType.toLowerCase().indexOf("application/json")>=0?o.send(JSON.stringify(s)):o.send(s),o}function c(e,t,n){var i=w.endpointStore.get(e),o=S[e].addToPath;return void 0!=o&&(i+="/"+o),b&&t&&(i=qq.obj2url(t,i)),n&&(i=qq.obj2url(n,i)),i}function d(e){return function(){4===r(e).readyState&&s(e)}}function p(e){var t=w.onProgress;t&&(r(e).upload.onprogress=function(n){n.lengthComputable&&t(e,n.loaded,n.total)})}function f(e){return function(){s(e)}}function q(e){return function(){s(e,!0)}}function h(e){var o=r(e),a=w.customHeaders,s=S[e].additionalHeaders||{},u=w.method,l={};i(o)||(w.acceptHeader&&o.setRequestHeader("Accept",w.acceptHeader),w.allowXRequestedWithAndCacheControl&&(w.cors.expected&&t()&&!n(a)||(o.setRequestHeader("X-Requested-With","XMLHttpRequest"),o.setRequestHeader("Cache-Control","no-cache"))),!w.contentType||"POST"!==u&&"PUT"!==u||o.setRequestHeader("Content-Type",w.contentType),qq.extend(l,qq.isFunction(a)?a(e):a),qq.extend(l,s),qq.each(l,function(e,t){o.setRequestHeader(e,t)}))}function m(e){return qq.indexOf(w.successfulResponseCodes[w.method],e)>=0}function g(e,t,n,i,o,r,a){S[e]={addToPath:n,additionalParams:i,additionalQueryParams:o,additionalHeaders:r,payload:a};var s=v.push(e);if(s<=w.maxConnections)return l(e,t)}var _,b,v=[],S={},w={acceptHeader:null,validMethods:["PATCH","POST","PUT"],method:"POST",contentType:"application/x-www-form-urlencoded",maxConnections:3,customHeaders:{},endpointStore:{},paramsStore:{},mandatedParams:{},allowXRequestedWithAndCacheControl:!0,successfulResponseCodes:{DELETE:[200,202,204],PATCH:[200,201,202,203,204],POST:[200,201,202,203,204],PUT:[200,201,202,203,204],GET:[200]},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onSend:function(e){},onComplete:function(e,t,n){},onProgress:null};if(qq.extend(w,e),_=w.log,qq.indexOf(w.validMethods,w.method)<0)throw new Error("'"+w.method+"' is not a supported method for this type of request!");b="GET"===w.method||"DELETE"===w.method,qq.extend(this,{initTransport:function(e){var t,n,i,o,r,a;return{withPath:function(e){return t=e,this},withParams:function(e){return n=e,this},withQueryParams:function(e){return a=e,this},withHeaders:function(e){return i=e,this},withPayload:function(e){return o=e,this},withCacheBuster:function(){return r=!0,this},send:function(s){return r&&qq.indexOf(["GET","DELETE"],w.method)>=0&&(n.qqtimestamp=(new Date).getTime()),g(e,s,t,n,a,i,o)}}},canceled:function(e){a(e)}})},qq.UploadHandler=function(e){"use strict";var t=e.proxy,n={},i=t.onCancel,o=t.getName;qq.extend(this,{add:function(e,t){n[e]=t,n[e].temp={}},cancel:function(e){var t=this,r=new qq.Promise,a=i(e,o(e),r);a.then(function(){t.isValid(e)&&(n[e].canceled=!0,t.expunge(e)),r.success()})},expunge:function(e){delete n[e]},getThirdPartyFileId:function(e){return n[e].key},isValid:function(e){return void 0!==n[e]},reset:function(){n={}},_getFileState:function(e){return n[e]},_setThirdPartyFileId:function(e,t){n[e].key=t},_wasCanceled:function(e){return!!n[e].canceled}})},qq.UploadHandlerController=function(e,t){"use strict";var n,i,o,r=this,a=!1,s=!1,u={paramsStore:{},maxConnections:3,chunking:{enabled:!1,multiple:{enabled:!1}},log:function(e,t){},onProgress:function(e,t,n,i){},onComplete:function(e,t,n,i){},onCancel:function(e,t){},onUploadPrep:function(e){},onUpload:function(e,t){},onUploadChunk:function(e,t,n){},onUploadChunkSuccess:function(e,t,n,i){},onAutoRetry:function(e,t,n,i){},onResume:function(e,t,n){},onUuidChanged:function(e,t){},getName:function(e){},setSize:function(e,t){},isQueued:function(e){},getIdsInProxyGroup:function(e){},getIdsInBatch:function(e){}},l={done:function(e,t,n,i){var r=o._getChunkData(e,t);o._getFileState(e).attemptingResume=!1,delete o._getFileState(e).temp.chunkProgress[t],o._getFileState(e).loaded+=r.size,u.onUploadChunkSuccess(e,o._getChunkDataForCallback(r),n,i)},finalize:function(e){var t=u.getSize(e),n=u.getName(e);i("All chunks have been uploaded for "+e+" - finalizing...."),o.finalizeChunks(e).then(function(r,a){i("Finalize successful for "+e);var s=p.normalizeResponse(r,!0);u.onProgress(e,n,t,t),o._maybeDeletePersistedChunkData(e),p.cleanup(e,s,a)},function(t,o){var r=p.normalizeResponse(t,!1);i("Problem finalizing chunks for file ID "+e+" - "+r.error,"error"),r.reset&&l.reset(e),u.onAutoRetry(e,n,r,o)||p.cleanup(e,r,o)})},handleFailure:function(e,t,n,r){var a=u.getName(t);i("Chunked upload request failed for "+t+", chunk "+e),o.clearCachedChunk(t,e);var d,f=p.normalizeResponse(n,!1);f.reset?l.reset(t):(d=qq.indexOf(o._getFileState(t).chunking.inProgress,e),d>=0&&(o._getFileState(t).chunking.inProgress.splice(d,1),o._getFileState(t).chunking.remaining.unshift(e))),o._getFileState(t).temp.ignoreFailure||(s&&(o._getFileState(t).temp.ignoreFailure=!0,i(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.",JSON.stringify(Object.keys(o._getXhrs(t))),JSON.stringify(o._getFileState(t).chunking.inProgress))),qq.each(o._getXhrs(t),function(e,n){i(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ",t,e,n.readyState)),n.abort(),n._cancelled=!0}),o.moveInProgressToRemaining(t),c.free(t,!0)),u.onAutoRetry(t,a,f,r)||p.cleanup(t,f,r))},hasMoreParts:function(e){return!!o._getFileState(e).chunking.remaining.length},nextPart:function(e){var t=o._getFileState(e).chunking.remaining.shift();return t>=o._getTotalChunks(e)&&(t=null),t},reset:function(e){i("Server or callback has ordered chunking effort to be restarted on next attempt for item ID "+e,"error"),o._maybeDeletePersistedChunkData(e),o.reevaluateChunking(e),o._getFileState(e).loaded=0},sendNext:function(e){var t=u.getSize(e),n=u.getName(e),r=l.nextPart(e),a=o._getChunkData(e,r),d=o._getFileState(e).attemptingResume,f=o._getFileState(e).chunking.inProgress||[];null==o._getFileState(e).loaded&&(o._getFileState(e).loaded=0),d&&u.onResume(e,n,a)===!1&&(l.reset(e),r=l.nextPart(e),a=o._getChunkData(e,r),d=!1),null==r&&0===f.length?l.finalize(e):(i(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.",e,r,a.start+1,a.end,t)),u.onUploadChunk(e,n,o._getChunkDataForCallback(a)),f.push(r),o._getFileState(e).chunking.inProgress=f,s&&c.open(e,r),s&&c.available()&&o._getFileState(e).chunking.remaining.length&&l.sendNext(e),0===a.blob.size?(i(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.",r,e),"error"),l.handleFailure(r,e,"File is no longer available",null)):o.uploadChunk(e,r,d).then(function(t,n){i("Chunked upload request succeeded for "+e+", chunk "+r),o.clearCachedChunk(e,r);var a=o._getFileState(e).chunking.inProgress||[],s=p.normalizeResponse(t,!0),u=qq.indexOf(a,r);i(qq.format("Chunk {} for file {} uploaded successfully.",r,e)),l.done(e,r,s,n),u>=0&&a.splice(u,1),o._maybePersistChunkedState(e),l.hasMoreParts(e)||0!==a.length?l.hasMoreParts(e)?l.sendNext(e):i(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}",e,JSON.stringify(a))):l.finalize(e)},function(t,n){l.handleFailure(r,e,t,n)}).done(function(){o.clearXhr(e,r)}))}},c={_open:[],_openChunks:{},_waiting:[],available:function(){var e=u.maxConnections,t=0,n=0;return qq.each(c._openChunks,function(e,i){t++,n+=i.length}),e-(c._open.length-t+n)},free:function(e,t){var n,r=!t,a=qq.indexOf(c._waiting,e),s=qq.indexOf(c._open,e);delete c._openChunks[e],p.getProxyOrBlob(e)instanceof qq.BlobProxy&&(i("Generated blob upload has ended for "+e+", disposing generated blob."),delete o._getFileState(e).file),a>=0?c._waiting.splice(a,1):r&&s>=0&&(c._open.splice(s,1),n=c._waiting.shift(),n>=0&&(c._open.push(n),p.start(n)))},getWaitingOrConnected:function(){var e=[];return qq.each(c._openChunks,function(t,n){n&&n.length&&e.push(parseInt(t))}),qq.each(c._open,function(t,n){c._openChunks[n]||e.push(parseInt(n))}),e=e.concat(c._waiting)},isUsingConnection:function(e){return qq.indexOf(c._open,e)>=0},open:function(e,t){return null==t&&c._waiting.push(e),!!c.available()&&(null==t?(c._waiting.pop(),c._open.push(e)):!function(){var n=c._openChunks[e]||[];n.push(t),c._openChunks[e]=n}(),!0)},reset:function(){c._waiting=[],c._open=[]}},d={send:function(e,t){o._getFileState(e).loaded=0,i("Sending simple upload request for "+e),o.uploadFile(e).then(function(n,o){i("Simple upload request succeeded for "+e);var r=p.normalizeResponse(n,!0),a=u.getSize(e);u.onProgress(e,t,a,a),p.maybeNewUuid(e,r),p.cleanup(e,r,o)},function(n,o){i("Simple upload request failed for "+e);var r=p.normalizeResponse(n,!1);u.onAutoRetry(e,t,r,o)||p.cleanup(e,r,o)})}},p={cancel:function(e){i("Cancelling "+e),u.paramsStore.remove(e),c.free(e)},cleanup:function(e,t,n){var i=u.getName(e);u.onComplete(e,i,t,n),o._getFileState(e)&&o._clearXhrs&&o._clearXhrs(e),c.free(e)},getProxyOrBlob:function(e){return o.getProxy&&o.getProxy(e)||o.getFile&&o.getFile(e)},initHandler:function(){var e=t?qq[t]:qq.traditional,n=qq.supportedFeatures.ajaxUploading?"Xhr":"Form";o=new e[n+"UploadHandler"](u,{getDataByUuid:u.getDataByUuid,getName:u.getName,getSize:u.getSize,getUuid:u.getUuid,log:i,onCancel:u.onCancel,onProgress:u.onProgress,onUuidChanged:u.onUuidChanged}),o._removeExpiredChunkingRecords&&o._removeExpiredChunkingRecords()},isDeferredEligibleForUpload:function(e){return u.isQueued(e)},maybeDefer:function(e,t){return t&&!o.getFile(e)&&t instanceof qq.BlobProxy?(u.onUploadPrep(e),i("Attempting to generate a blob on-demand for "+e),t.create().then(function(t){i("Generated an on-demand blob for "+e),o.updateBlob(e,t),u.setSize(e,t.size),o.reevaluateChunking(e),p.maybeSendDeferredFiles(e)},function(t){var o={};t&&(o.error=t),i(qq.format("Failed to generate blob for ID {}. Error message: {}.",e,t),"error"),u.onComplete(e,u.getName(e),qq.extend(o,n),null),p.maybeSendDeferredFiles(e),c.free(e)}),!1):p.maybeSendDeferredFiles(e)},maybeSendDeferredFiles:function(e){var t=u.getIdsInProxyGroup(e),n=!1;return t&&t.length?(i("Maybe ready to upload proxy group file "+e),qq.each(t,function(t,i){if(p.isDeferredEligibleForUpload(i)&&o.getFile(i))n=i===e,p.now(i);else if(p.isDeferredEligibleForUpload(i))return!1})):(n=!0,p.now(e)),n},maybeNewUuid:function(e,t){void 0!==t.newUuid&&u.onUuidChanged(e,t.newUuid)},normalizeResponse:function(e,t){var n=e;return qq.isObject(e)||(n={},qq.isString(e)&&!t&&(n.error=e)),n.success=t,n},now:function(e){var t=u.getName(e);if(!r.isValid(e))throw new qq.Error(e+" is not a valid file ID to upload!");u.onUpload(e,t),a&&o._shouldChunkThisFile(e)?l.sendNext(e):d.send(e,t)},start:function(e){var t=p.getProxyOrBlob(e);return t?p.maybeDefer(e,t):(p.now(e),!0)}};qq.extend(this,{add:function(e,t){o.add.apply(this,arguments)},upload:function(e){return!!c.open(e)&&p.start(e)},retry:function(e){return s&&(o._getFileState(e).temp.ignoreFailure=!1),c.isUsingConnection(e)?p.start(e):r.upload(e)},cancel:function(e){var t=o.cancel(e);qq.isGenericPromise(t)?t.then(function(){p.cancel(e)}):t!==!1&&p.cancel(e)},cancelAll:function(){var e,t=c.getWaitingOrConnected();if(t.length)for(e=t.length-1;e>=0;e--)r.cancel(t[e]);c.reset()},getFile:function(e){return o.getProxy&&o.getProxy(e)?o.getProxy(e).referenceBlob:o.getFile&&o.getFile(e);
+},isProxied:function(e){return!(!o.getProxy||!o.getProxy(e))},getInput:function(e){if(o.getInput)return o.getInput(e)},reset:function(){i("Resetting upload handler"),r.cancelAll(),c.reset(),o.reset()},expunge:function(e){if(r.isValid(e))return o.expunge(e)},isValid:function(e){return o.isValid(e)},getResumableFilesData:function(){return o.getResumableFilesData?o.getResumableFilesData():[]},getThirdPartyFileId:function(e){if(r.isValid(e))return o.getThirdPartyFileId(e)},pause:function(e){return!!(r.isResumable(e)&&o.pause&&r.isValid(e)&&o.pause(e))&&(c.free(e),o.moveInProgressToRemaining(e),!0)},isResumable:function(e){return!!o.isResumable&&o.isResumable(e)}}),qq.extend(u,e),i=u.log,a=u.chunking.enabled&&qq.supportedFeatures.chunking,s=a&&u.chunking.concurrent.enabled,n=function(){var e={};return e[u.preventRetryParam]=!0,e}(),p.initHandler()},qq.WindowReceiveMessage=function(e){"use strict";var t={log:function(e,t){}},n={};qq.extend(t,e),qq.extend(this,{receiveMessage:function(e,t){var i=function(e){t(e.data)};window.postMessage?n[e]=qq(window).attach("message",i):log("iframe message passing not supported in this browser!","error")},stopReceivingMessages:function(e){if(window.postMessage){var t=n[e];t&&t()}}})},qq.FormUploadHandler=function(e){"use strict";function t(e){delete c[e],p&&(clearTimeout(d[e]),delete d[e],m.stopReceivingMessages(e));var t=document.getElementById(a._getIframeName(e));t&&(t.setAttribute("src","javascript:false;"),qq(t).remove())}function n(e){return e.split("_")[0]}function i(e){var t=qq.toElement("");return t.setAttribute("id",e),t.style.display="none",document.body.appendChild(t),t}function o(e,t){var i=e.id,o=n(i),r=q(o);l[r]=t,c[o]=qq(e).attach("load",function(){a.getInput(o)&&(h("Received iframe load event for CORS upload request (iframe name "+i+")"),d[i]=setTimeout(function(){var e="No valid message received from loaded iframe for iframe name "+i;h(e,"error"),t({error:e})},1e3))}),m.receiveMessage(i,function(e){h("Received the following window message: '"+e+"'");var t,o=(n(i),a._parseJsonResponse(e)),r=o.uuid;r&&l[r]?(h("Handling response for iframe name "+i),clearTimeout(d[i]),delete d[i],a._detachLoadEvent(i),t=l[r],delete l[r],m.stopReceivingMessages(i),t(o)):r||h("'"+e+"' does not contain a UUID - ignoring.")})}var r=e.options,a=this,s=e.proxy,u=qq.getUniqueId(),l={},c={},d={},p=r.isCors,f=r.inputName,q=s.getUuid,h=s.log,m=new qq.WindowReceiveMessage({log:h});qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,n){e.add(t,{input:n}),n.setAttribute("name",f),n.parentNode&&qq(n).remove()},expunge:function(n){t(n),e.expunge(n)},isValid:function(t){return e.isValid(t)&&void 0!==a._getFileState(t).input}}}),qq.extend(this,{getInput:function(e){return a._getFileState(e).input},_attachLoadEvent:function(e,t){var n;p?o(e,t):c[e.id]=qq(e).attach("load",function(){if(h("Received response for "+e.id),e.parentNode){try{if(e.contentDocument&&e.contentDocument.body&&"false"==e.contentDocument.body.innerHTML)return}catch(e){h("Error when attempting to access iframe during handling of upload response ("+e.message+")","error"),n={success:!1}}t(n)}})},_createIframe:function(e){var t=a._getIframeName(e);return i(t)},_detachLoadEvent:function(e){void 0!==c[e]&&(c[e](),delete c[e])},_getIframeName:function(e){return e+"_"+u},_initFormForUpload:function(e){var t=e.method,n=e.endpoint,i=e.params,o=e.paramsInBody,r=e.targetName,a=qq.toElement(""),s=n;return o?qq.obj2Inputs(i,a):s=qq.obj2url(i,n),a.setAttribute("action",s),a.setAttribute("target",r),a.style.display="none",document.body.appendChild(a),a},_parseJsonResponse:function(e){var t={};try{t=qq.parseJson(e)}catch(e){h("Error when attempting to parse iframe upload response ("+e.message+")","error")}return t}})},qq.XhrUploadHandler=function(e){"use strict";function t(e){qq.each(n._getXhrs(e),function(t,i){var o=n._getAjaxRequester(e,t);i.onreadystatechange=null,i.upload.onprogress=null,i.abort(),o&&o.canceled&&o.canceled(e)})}var n=this,i=e.options.namespace,o=e.proxy,r=e.options.chunking,a=e.options.resume,s=r&&e.options.chunking.enabled&&qq.supportedFeatures.chunking,u=a&&e.options.resume.enabled&&s&&qq.supportedFeatures.resume,l=o.getName,c=o.getSize,d=o.getUuid,p=o.getEndpoint,f=o.getDataByUuid,q=o.onUuidChanged,h=o.onProgress,m=o.log;qq.extend(this,new qq.UploadHandler(e)),qq.override(this,function(e){return{add:function(t,i){if(qq.isFile(i)||qq.isBlob(i))e.add(t,{file:i});else{if(!(i instanceof qq.BlobProxy))throw new Error("Passed obj is not a File, Blob, or proxy");e.add(t,{proxy:i})}n._initTempState(t),u&&n._maybePrepareForResume(t)},expunge:function(i){t(i),n._maybeDeletePersistedChunkData(i),n._clearXhrs(i),e.expunge(i)}}}),qq.extend(this,{clearCachedChunk:function(e,t){delete n._getFileState(e).temp.cachedChunks[t]},clearXhr:function(e,t){var i=n._getFileState(e).temp;i.xhrs&&delete i.xhrs[t],i.ajaxRequesters&&delete i.ajaxRequesters[t]},finalizeChunks:function(e,t){var i=n._getTotalChunks(e)-1,o=n._getXhr(e,i);return t?(new qq.Promise).success(t(o),o):(new qq.Promise).success({},o)},getFile:function(e){return n.isValid(e)&&n._getFileState(e).file},getProxy:function(e){return n.isValid(e)&&n._getFileState(e).proxy},getResumableFilesData:function(){var e=[];return n._iterateResumeRecords(function(t,i){n.moveInProgressToRemaining(null,i.chunking.inProgress,i.chunking.remaining);var o={name:i.name,remaining:i.chunking.remaining,size:i.size,uuid:i.uuid};i.key&&(o.key=i.key),e.push(o)}),e},isResumable:function(e){return!!r&&n.isValid(e)&&!n._getFileState(e).notResumable},moveInProgressToRemaining:function(e,t,i){var o=t||n._getFileState(e).chunking.inProgress,r=i||n._getFileState(e).chunking.remaining;o&&(m(qq.format("Moving these chunks from in-progress {}, to remaining.",JSON.stringify(o))),o.reverse(),qq.each(o,function(e,t){r.unshift(t)}),o.length=0)},pause:function(e){if(n.isValid(e))return m(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.",e,l(e))),n._getFileState(e).paused=!0,t(e),!0},reevaluateChunking:function(e){if(r&&n.isValid(e)){var t,i,o=n._getFileState(e);if(delete o.chunking,o.chunking={},t=n._getTotalChunks(e),t>1||r.mandatory){for(o.chunking.enabled=!0,o.chunking.parts=t,o.chunking.remaining=[],i=0;i=o?o:s+i,l=n._getTotalChunks(e),d=this._getFileState(e).temp.cachedChunks,p=d[t]||qq.sliceBlob(a,s,u);return d[t]=p,{part:t,start:s,end:u,count:l,blob:p,size:u-s}},_getChunkDataForCallback:function(e){return{partIndex:e.part,startByte:e.start+1,endByte:e.end,totalParts:e.count}},_getLocalStorageId:function(e){var t="5.0",n=l(e),o=c(e),a=r.partSize,s=p(e);return qq.format("qq{}resume{}-{}-{}-{}-{}",i,t,n,o,a,s)},_getMimeType:function(e){return n.getFile(e).type},_getPersistableData:function(e){return n._getFileState(e).chunking},_getTotalChunks:function(e){if(r){var t=c(e),n=r.partSize;return Math.ceil(t/n)}},_getXhr:function(e,t){var i=null==t?-1:t;return n._getFileState(e).temp.xhrs[i]},_getXhrs:function(e){return n._getFileState(e).temp.xhrs},_iterateResumeRecords:function(e){u&&qq.each(localStorage,function(t,n){if(0===t.indexOf(qq.format("qq{}resume",i))){var o=JSON.parse(n);e(t,o)}})},_initTempState:function(e){n._getFileState(e).temp={ajaxRequesters:{},chunkProgress:{},xhrs:{},cachedChunks:{}}},_markNotResumable:function(e){n._getFileState(e).notResumable=!0},_maybeDeletePersistedChunkData:function(e){var t;return!!(u&&n.isResumable(e)&&(t=n._getLocalStorageId(e),t&&localStorage.getItem(t)))&&(localStorage.removeItem(t),!0)},_maybePrepareForResume:function(e){var t,i,o=n._getFileState(e);u&&void 0===o.key&&(t=n._getLocalStorageId(e),i=localStorage.getItem(t),i&&(i=JSON.parse(i),f(i.uuid)?n._markNotResumable(e):(m(qq.format("Identified file with ID {} and name of {} as resumable.",e,l(e))),q(e,i.uuid),o.key=i.key,o.chunking=i.chunking,o.loaded=i.loaded,o.attemptingResume=!0,n.moveInProgressToRemaining(e))))},_maybePersistChunkedState:function(e){var t,i,o=n._getFileState(e);if(u&&n.isResumable(e)){t=n._getLocalStorageId(e),i={name:l(e),size:c(e),uuid:d(e),key:o.key,chunking:o.chunking,loaded:o.loaded,lastUpdated:Date.now()};try{localStorage.setItem(t,JSON.stringify(i))}catch(t){m(qq.format("Unable to save resume data for '{}' due to error: '{}'.",e,t.toString()),"warn")}}},_registerProgressHandler:function(e,t,i){var o=n._getXhr(e,t),r=l(e),a={simple:function(t,n){var i=c(e);t===n?h(e,r,i,i):h(e,r,t>=i?i-1:t,i)},chunked:function(o,a){var s=n._getFileState(e).temp.chunkProgress,u=n._getFileState(e).loaded,l=o,d=a,p=c(e),f=l-(d-i),q=u;s[t]=f,qq.each(s,function(e,t){q+=t}),h(e,r,q,p)}};o.upload.onprogress=function(e){if(e.lengthComputable){var t=null==i?"simple":"chunked";a[t](e.loaded,e.total)}}},_registerXhr:function(e,t,i,o){var r=null==t?-1:t,a=n._getFileState(e).temp;return a.xhrs=a.xhrs||{},a.ajaxRequesters=a.ajaxRequesters||{},a.xhrs[r]=i,o&&(a.ajaxRequesters[r]=o),i},_removeExpiredChunkingRecords:function(){var e=a.recordsExpireIn;n._iterateResumeRecords(function(t,n){var i=new Date(n.lastUpdated);i.setDate(i.getDate()+e),i.getTime()<=Date.now()&&(m("Removing expired resume record with key "+t),localStorage.removeItem(t))})},_shouldChunkThisFile:function(e){var t=n._getFileState(e);return t.chunking||n.reevaluateChunking(e),t.chunking.enabled}})},qq.DeleteFileAjaxRequester=function(e){"use strict";function t(){return"POST"===i.method.toUpperCase()?{_method:"DELETE"}:{}}var n,i={method:"DELETE",uuidParamName:"qquuid",endpointStore:{},maxConnections:3,customHeaders:function(e){return{}},paramsStore:{},cors:{expected:!1,sendCredentials:!1},log:function(e,t){},onDelete:function(e){},onDeleteComplete:function(e,t,n){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["POST","DELETE"],method:i.method,endpointStore:i.endpointStore,paramsStore:i.paramsStore,mandatedParams:t(),maxConnections:i.maxConnections,customHeaders:function(e){return i.customHeaders.get(e)},log:i.log,onSend:i.onDelete,onComplete:i.onDeleteComplete,cors:i.cors})),qq.extend(this,{sendDelete:function(e,t,o){var r=o||{};i.log("Submitting delete file request for "+e),"DELETE"===i.method?n.initTransport(e).withPath(t).withParams(r).send():(r[i.uuidParamName]=t,n.initTransport(e).withParams(r).send())}})},function(){function e(e){var t,n=e.naturalWidth,i=e.naturalHeight,o=document.createElement("canvas");return n*i>1048576&&(o.width=o.height=1,t=o.getContext("2d"),t.drawImage(e,-n+1,0),0===t.getImageData(0,0,1,1).data[3])}function t(e,t,n){var i,o,r,a,s=document.createElement("canvas"),u=0,l=n,c=n;for(s.width=1,s.height=n,i=s.getContext("2d"),i.drawImage(e,0,0),o=i.getImageData(0,0,1,n).data;c>u;)r=o[4*(c-1)+3],0===r?l=c:u=c,c=l+u>>1;return a=c/n,0===a?1:a}function n(e,t,n,i){var r=document.createElement("canvas"),a=n.mime||"image/jpeg",s=new qq.Promise;return o(e,t,r,n,i).then(function(){s.success(r.toDataURL(a,n.quality||.8))}),s}function i(e){var t=5241e3;if(!qq.ios())throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");if(e.origHeight*e.origWidth>t)return{newHeight:Math.round(Math.sqrt(t*(e.origHeight/e.origWidth))),newWidth:Math.round(Math.sqrt(t*(e.origWidth/e.origHeight)))}}function o(n,o,s,u,l){var c,d=n.naturalWidth,p=n.naturalHeight,f=u.width,q=u.height,h=s.getContext("2d"),m=new qq.Promise;return h.save(),u.resize?r({blob:o,canvas:s,image:n,imageHeight:p,imageWidth:d,orientation:u.orientation,resize:u.resize,targetHeight:q,targetWidth:f}):(qq.supportedFeatures.unlimitedScaledImageSize||(c=i({origWidth:f,origHeight:q}),c&&(qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h",f,q,c.newWidth,c.newHeight),"warn"),f=c.newWidth,q=c.newHeight)),a(s,f,q,u.orientation),qq.ios()?!function(){e(n)&&(d/=2,p/=2);var i,o,r,a=1024,s=document.createElement("canvas"),u=l?t(n,d,p):1,c=Math.ceil(a*f/d),m=Math.ceil(a*q/p/u),g=0,_=0;for(s.width=s.height=a,i=s.getContext("2d");gc&&(u=c,l=s*u/a<<0),d&&l>d&&(l=d,u=a*l/s<<0),i={width:u,height:l},qq.each(t,function(e,t){i[e]=t}),"img"===f?!function(){var t=e.src;n(r.srcImage,r.blob,i,p).then(function(n){e.src=n,t===e.src&&e.onload()})}():"canvas"===f&&o(this.srcImage,this.blob,e,i,p),void("function"==typeof this.onrender&&this.onrender(e)))},qq.MegaPixImage=s}(),qq.ImageGenerator=function(e){"use strict";function t(e){return"img"===e.tagName.toLowerCase()}function n(e){return"canvas"===e.tagName.toLowerCase()}function i(){return void 0!==(new Image).crossOrigin}function o(){var e=document.createElement("canvas");return e.getContext&&e.getContext("2d")}function r(e){var t=e.split("/"),n=t[t.length-1].split("?")[0],i=qq.getExtension(n);switch(i=i&&i.toLowerCase()){case"jpeg":case"jpg":return"image/jpeg";case"png":return"image/png";case"bmp":return"image/bmp";case"gif":return"image/gif";case"tiff":case"tif":return"image/tiff"}}function a(e){var t,n,i,o=document.createElement("a");return o.href=e,t=o.protocol,i=o.port,n=o.hostname,t.toLowerCase()!==window.location.protocol.toLowerCase()||(n.toLowerCase()!==window.location.hostname.toLowerCase()||i!==window.location.port&&!qq.ie())}function s(t,n){t.onload=function(){t.onload=null,t.onerror=null,n.success(t)},t.onerror=function(){t.onload=null,t.onerror=null,e("Problem drawing thumbnail!","error"),n.failure(t,"Problem drawing thumbnail!")}}function u(e,t){e.qqImageRendered=function(){t.success(e)}}function l(i,o){var r=t(i)||n(i);return t(i)?s(i,o):n(i)?u(i,o):(o.failure(i),e(qq.format("Element container of type {} is not supported!",i.tagName),"error")),r}function c(t,n,i){var o=new qq.Promise,r=new qq.Identify(t,e),a=i.maxSize,s=null==i.orient||i.orient,u=function(){n.onerror=null,n.onload=null,e("Could not render preview, file may be too large!","error"),o.failure(n,"Browser cannot render image!")};return r.isPreviewable().then(function(r){var c={parse:function(){return(new qq.Promise).success()}},d=s?new qq.Exif(t,e):c,p=new qq.MegaPixImage(t,u);l(n,o)&&d.parse().then(function(e){var t=e&&e.Orientation;p.render(n,{maxWidth:a,maxHeight:a,orientation:t,mime:r,resize:i.customResizeFunction})},function(t){e(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.",t)),p.render(n,{maxWidth:a,maxHeight:a,mime:r,resize:i.customResizeFunction})})},function(){e("Not previewable"),o.failure(n,"Not previewable")}),o}function d(e,t,n,i,o){var s=new Image,u=new qq.Promise;l(s,u),a(e)&&(s.crossOrigin="anonymous"),s.src=e,u.then(function(){l(t,n);var a=new qq.MegaPixImage(s);a.render(t,{maxWidth:i,maxHeight:i,mime:r(e),resize:o})},n.failure)}function p(e,t,n,i){l(t,n),qq(t).css({maxWidth:i+"px",maxHeight:i+"px"}),t.src=e}function f(e,r,s){var u=new qq.Promise,c=s.scale,f=c?s.maxSize:null;return c&&t(r)?o()?a(e)&&!i()?p(e,r,u,f):d(e,r,u,f):p(e,r,u,f):n(r)?d(e,r,u,f):l(r,u)&&(r.src=e),u}qq.extend(this,{generate:function(t,n,i){return qq.isString(t)?(e("Attempting to update thumbnail based on server response."),f(t,n,i||{})):(e("Attempting to draw client-side image preview."),c(t,n,i||{}))}}),this._testing={},this._testing.isImg=t,this._testing.isCanvas=n,this._testing.isCrossOrigin=a,this._testing.determineMimeOfFileName=r},qq.Exif=function(e,t){"use strict";function n(e){for(var t=0,n=0;e.length>0;)t+=parseInt(e.substring(0,2),16)*Math.pow(2,n),e=e.substring(2,e.length),n+=8;return t}function i(t,n){var o=t,r=n;return void 0===o&&(o=2,r=new qq.Promise),qq.readBlobToHex(e,o,4).then(function(e){var t,n=/^ffe([0-9])/.exec(e);n?"1"!==n[1]?(t=parseInt(e.slice(4,8),16),i(o+t+2,r)):r.success(o):r.failure("No EXIF header to be found!")}),r}function o(){var t=new qq.Promise;return qq.readBlobToHex(e,0,6).then(function(e){0!==e.indexOf("ffd8")?t.failure("Not a valid JPEG!"):i().then(function(e){t.success(e)},function(e){t.failure(e)})}),t}function r(t){var n=new qq.Promise;return qq.readBlobToHex(e,t+10,2).then(function(e){n.success("4949"===e)}),n}function a(t,i){var o=new qq.Promise;return qq.readBlobToHex(e,t+18,2).then(function(e){return i?o.success(n(e)):void o.success(parseInt(e,16))}),o}function s(t,n){var i=t+20,o=12*n;return qq.readBlobToHex(e,i,o)}function u(e){for(var t=[],n=0;n+24<=e.length;)t.push(e.slice(n,n+24)),n+=24;return t}function l(e,t){var i=16,o=qq.extend([],c),r={};return qq.each(t,function(t,a){var s,u,l,c=a.slice(0,4),p=e?n(c):parseInt(c,16),f=o.indexOf(p);if(f>=0&&(u=d[p].name,l=d[p].bytes,s=a.slice(i,i+2*l),r[u]=e?n(s):parseInt(s,16),o.splice(f,1)),0===o.length)return!1}),r}var c=[274],d={274:{name:"Orientation",bytes:2}};qq.extend(this,{parse:function(){var n=new qq.Promise,i=function(e){t(qq.format("EXIF header parse failed: '{}' ",e)),n.failure(e)};return o().then(function(o){t(qq.format("Moving forward with EXIF header parsing for '{}'",void 0===e.name?"blob":e.name)),r(o).then(function(e){t(qq.format("EXIF Byte order is {} endian",e?"little":"big")),a(o,e).then(function(r){t(qq.format("Found {} APP1 directory entries",r)),s(o,r).then(function(i){var o=u(i),r=l(e,o);t("Successfully parsed some EXIF tags"),n.success(r)},i)},i)},i)},i),n}}),this._testing={},this._testing.parseLittleEndian=n},qq.Identify=function(e,t){"use strict";function n(e,t){var n=!1,i=[].concat(e);return qq.each(i,function(e,i){if(0===t.indexOf(i))return n=!0,!1}),n}qq.extend(this,{isPreviewable:function(){var i=this,o=new qq.Promise,r=!1,a=void 0===e.name?"blob":e.name;return t(qq.format("Attempting to determine if {} can be rendered in this browser",a)),t("First pass: check type attribute of blob object."),this.isPreviewableSync()?(t("Second pass: check for magic bytes in file header."),qq.readBlobToHex(e,0,4).then(function(e){qq.each(i.PREVIEWABLE_MIME_TYPES,function(t,i){if(n(i,e))return("image/tiff"!==t||qq.supportedFeatures.tiffPreviews)&&(r=!0,o.success(t)),!1}),t(qq.format("'{}' is {} able to be rendered in this browser",a,r?"":"NOT")),r||o.failure()},function(){t("Error reading file w/ name '"+a+"'. Not able to be rendered in this browser."),o.failure()})):o.failure(),o},isPreviewableSync:function(){var n=e.type,i=qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES),n)>=0,o=!1,r=void 0===e.name?"blob":e.name;return i&&(o="image/tiff"!==n||qq.supportedFeatures.tiffPreviews),!o&&t(r+" is not previewable in this browser per the blob's type attr"),o}})},qq.Identify.prototype.PREVIEWABLE_MIME_TYPES={"image/jpeg":"ffd8ff","image/gif":"474946","image/png":"89504e","image/bmp":"424d","image/tiff":["49492a00","4d4d002a"]},qq.ImageValidation=function(e,t){"use strict";function n(e){var t=!1;return qq.each(e,function(e,n){if(n>0)return t=!0,!1}),t}function i(){var n=new qq.Promise;return new qq.Identify(e,t).isPreviewable().then(function(){var i=new Image,o=window.URL&&window.URL.createObjectURL?window.URL:window.webkitURL&&window.webkitURL.createObjectURL?window.webkitURL:null;o?(i.onerror=function(){t("Cannot determine dimensions for image. May be too large.","error"),n.failure()},i.onload=function(){n.success({width:this.width,height:this.height})},i.src=o.createObjectURL(e)):(t("No createObjectURL function available to generate image URL!","error"),n.failure())},n.failure),n}function o(e,t){var n;return qq.each(e,function(e,i){if(i>0){var o=/(max|min)(Width|Height)/.exec(e),r=o[2].charAt(0).toLowerCase()+o[2].slice(1),a=t[r];switch(o[1]){case"min":if(ai)return n=e,!1}}}),n}this.validate=function(e){var r=new qq.Promise;return t("Attempting to validate image."),n(e)?i().then(function(t){var n=o(e,t);n?r.failure(n):r.success()},r.success):r.success(),r}},qq.Session=function(e){"use strict";function t(e){return!!qq.isArray(e)||void i.log("Session response is not an array.","error")}function n(e,n,o,r){var a=!1;n=n&&t(e),n&&qq.each(e,function(e,t){if(null==t.uuid)a=!0,i.log(qq.format("Session response item {} did not include a valid UUID - ignoring.",e),"error");else if(null==t.name)a=!0,i.log(qq.format("Session response item {} did not include a valid name - ignoring.",e),"error");else try{return i.addFileRecord(t),!0}catch(e){a=!0,i.log(e.message,"error")}return!1}),r[n&&!a?"success":"failure"](e,o)}var i={endpoint:null,params:{},customHeaders:{},cors:{},addFileRecord:function(e){},log:function(e,t){}};qq.extend(i,e,!0),this.refresh=function(){var e=new qq.Promise,t=function(t,i,o){n(t,i,o,e)},o=qq.extend({},i),r=new qq.SessionAjaxRequester(qq.extend(o,{onComplete:t}));return r.queryServer(),e}},qq.SessionAjaxRequester=function(e){"use strict";function t(e,t,n){var o=null;if(null!=t.responseText)try{o=qq.parseJson(t.responseText)}catch(e){i.log("Problem parsing session response: "+e.message,"error"),n=!0}i.onComplete(o,!n,t)}var n,i={endpoint:null,customHeaders:{},params:{},cors:{expected:!1,sendCredentials:!1},onComplete:function(e,t,n){},log:function(e,t){}};qq.extend(i,e),n=qq.extend(this,new qq.AjaxRequester({acceptHeader:"application/json",validMethods:["GET"],method:"GET",endpointStore:{get:function(){return i.endpoint}},customHeaders:i.customHeaders,log:i.log,onComplete:t,cors:i.cors})),qq.extend(this,{queryServer:function(){var e=qq.extend({},i.params);i.log("Session query request."),n.initTransport("sessionRefresh").withParams(e).withCacheBuster().send()}})},qq.Scaler=function(e,t){"use strict";var n=e.customResizer,i=e.sendOriginal,o=e.orient,r=e.defaultType,a=e.defaultQuality/100,s=e.failureText,u=e.includeExif,l=this._getSortedSizes(e.sizes);qq.extend(this,{enabled:qq.supportedFeatures.scaling&&l.length>0,getFileRecords:function(e,c,d){var p=this,f=[],q=d.blob?d.blob:d,h=new qq.Identify(q,t);return h.isPreviewableSync()?(qq.each(l,function(e,i){var l=p._determineOutputType({defaultType:r,requestedType:i.type,refType:q.type});f.push({uuid:qq.getUniqueId(),name:p._getName(c,{name:i.name,type:l,refType:q.type}),blob:new qq.BlobProxy(q,qq.bind(p._generateScaledImage,p,{customResizeFunction:n,maxSize:i.maxSize,orient:o,type:l,quality:a,failedText:s,includeExif:u,log:t}))})}),f.push({uuid:e,name:c,size:q.size,blob:i?q:null})):f.push({uuid:e,name:c,size:q.size,blob:q}),f},handleNewFile:function(e,t,n,i,o,r,a,s){var u=this,l=(e.qqButtonId||e.blob&&e.blob.qqButtonId,[]),c=null,d=s.addFileToHandler,p=s.uploadData,f=s.paramsStore,q=qq.getUniqueId();qq.each(u.getFileRecords(n,t,e),function(e,t){var n,i=t.size;t.blob instanceof qq.BlobProxy&&(i=-1),n=p.addFile({uuid:t.uuid,name:t.name,size:i,batchId:r,proxyGroupId:q}),t.blob instanceof qq.BlobProxy?l.push(n):c=n,t.blob?(d(n,t.blob),o.push({id:n,file:t.blob})):p.setStatus(n,qq.status.REJECTED)}),null!==c&&(qq.each(l,function(e,t){var n={qqparentuuid:p.retrieve({id:c}).uuid,qqparentsize:p.retrieve({id:c}).size};n[a]=p.retrieve({id:t}).uuid,p.setParentId(t,c),f.addReadOnly(t,n)}),l.length&&!function(){var e={};e[a]=p.retrieve({id:c}).uuid,f.addReadOnly(c,e)}())}})},qq.extend(qq.Scaler.prototype,{scaleImage:function(e,t,n){"use strict";if(!qq.supportedFeatures.scaling)throw new qq.Error("Scaling is not supported in this browser!");var i=new qq.Promise,o=n.log,r=n.getFile(e),a=n.uploadData.retrieve({id:e}),s=a&&a.name,u=a&&a.uuid,l={customResizer:t.customResizer,sendOriginal:!1,orient:t.orient,defaultType:t.type||null,defaultQuality:t.quality,failedToScaleText:"Unable to scale",sizes:[{name:"",maxSize:t.maxSize}]},c=new qq.Scaler(l,o);return qq.Scaler&&qq.supportedFeatures.imagePreviews&&r?qq.bind(function(){var t=c.getFileRecords(u,s,r)[0];t&&t.blob instanceof qq.BlobProxy?t.blob.create().then(i.success,i.failure):(o(e+" is not a scalable image!","error"),i.failure())},this)():(i.failure(),o("Could not generate requested scaled image for "+e+". Scaling is either not possible in this browser, or the file could not be located.","error")),i},_determineOutputType:function(e){"use strict";var t=e.requestedType,n=e.defaultType,i=e.refType;return n||t?t&&qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES),t)>=0?"image/tiff"===t?qq.supportedFeatures.tiffPreviews?t:n:t:n:"image/jpeg"!==i?"image/png":i},_getName:function(e,t){"use strict";var n=e.lastIndexOf("."),i=t.type||"image/png",o=t.refType,r="",a=qq.getExtension(e),s="";return t.name&&t.name.trim().length&&(s=" ("+t.name+")"),n>=0?(r=e.substr(0,n),o!==i&&(a=i.split("/")[1]),r+=s+"."+a):r=e+s,r},_getSortedSizes:function(e){"use strict";return e=qq.extend([],e),e.sort(function(e,t){return e.maxSize>t.maxSize?1:e.maxSize=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),n=e.split(",")[0].split(":")[1].split(";")[0],i=new ArrayBuffer(t.length),o=new Uint8Array(i),qq.each(t,function(e,t){o[e]=t.charCodeAt(0)}),this._createBlob(i,n)},_createBlob:function(e,t){"use strict";var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})}}),qq.ExifRestorer=function(){var e={};return e.KEY_STR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e.encode64=function(e){var t,n,i,o,r,a="",s="",u="",l=0;do t=e[l++],n=e[l++],s=e[l++],i=t>>2,o=(3&t)<<4|n>>4,r=(15&n)<<2|s>>6,u=63&s,isNaN(n)?r=u=64:isNaN(s)&&(u=64),a=a+this.KEY_STR.charAt(i)+this.KEY_STR.charAt(o)+this.KEY_STR.charAt(r)+this.KEY_STR.charAt(u),t=n=s="",i=o=r=u="";while(le.length)break}return n},e.decode64=function(e){var t,n,i,o,r,a="",s="",u=0,l=[],c=/[^A-Za-z0-9\+\/\=]/g;if(c.exec(e))throw new Error("There were invalid base64 characters in the input text. Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");do i=this.KEY_STR.indexOf(e.charAt(u++)),o=this.KEY_STR.indexOf(e.charAt(u++)),r=this.KEY_STR.indexOf(e.charAt(u++)),s=this.KEY_STR.indexOf(e.charAt(u++)),t=i<<2|o>>4,n=(15&o)<<4|r>>2,a=(3&r)<<6|s,l.push(t),64!=r&&l.push(n),64!=s&&l.push(a),t=n=a="",i=o=r=s="";while(u=0)return n=!1,!1}),n},l=function(e){p(e,-1,-1),delete n[e]},c=function(e,t,n){(0===t.length||u(t,n))&&(s(o,o),this.reset())},d=function(e){var i=t(e);i>0&&(p(e,0,i),n[e]={loaded:0,total:i})},p=function(e,t,r){var a=n[e]?n[e].loaded:0,u=n[e]?n[e].total:0;t===-1&&r===-1?(i-=a,o-=u):(t&&(i+=t-a),r&&(o+=r-u)),s(i,o)};qq.extend(this,{onAllComplete:c,onStatusChange:function(e,t,n){n===qq.status.CANCELED||n===qq.status.REJECTED?l(e):n===qq.status.SUBMITTING&&d(e)},onIndividualProgress:function(e,t,i){p(e,t,i),n[e]={loaded:t,total:i}},onNewSize:function(e){d(e)},reset:function(){n={},i=0,o=0}})},qq.PasteSupport=function(e){"use strict";function t(e){return e.type&&0===e.type.indexOf("image/")}function n(){r=qq(o.targetElement).attach("paste",function(e){var n=e.clipboardData;n&&qq.each(n.items,function(e,n){if(t(n)){var i=n.getAsFile();o.callbacks.pasteReceived(i)}})})}function i(){r&&r()}var o,r;o={targetElement:null,callbacks:{log:function(e,t){},pasteReceived:function(e){}}},qq.extend(o,e),n(),qq.extend(this,{reset:function(){i()}})},qq.FormSupport=function(e,t,n){"use strict";function i(e){e.getAttribute("action")&&(s.newEndpoint=e.getAttribute("action"))}function o(e,t){return!(e.checkValidity&&!e.checkValidity())||(n("Form did not pass validation checks - will not upload.","error"),void t())}function r(e){var n=e.submit;
+qq(e).attach("submit",function(i){i=i||window.event,i.preventDefault?i.preventDefault():i.returnValue=!1,o(e,n)&&t()}),e.submit=function(){o(e,n)&&t()}}function a(e){return e&&(qq.isString(e)&&(e=document.getElementById(e)),e&&(n("Attaching to form element."),i(e),u&&r(e))),e}var s=this,u=e.interceptSubmit,l=e.element,c=e.autoUpload;qq.extend(this,{newEndpoint:null,newAutoUpload:c,attachedToForm:!1,getFormInputsAsObject:function(){return null==l?null:s._form2Obj(l)}}),l=a(l),this.attachedToForm=!!l},qq.extend(qq.FormSupport.prototype,{_form2Obj:function(e){"use strict";var t={},n=function(e){var t=["button","image","reset","submit"];return qq.indexOf(t,e.toLowerCase())<0},i=function(e){return qq.indexOf(["checkbox","radio"],e.toLowerCase())>=0},o=function(e){return!(!i(e.type)||e.checked)||e.disabled&&"hidden"!==e.type.toLowerCase()},r=function(e){var t=null;return qq.each(qq(e).children(),function(e,n){if("option"===n.tagName.toLowerCase()&&n.selected)return t=n.value,!1}),t};return qq.each(e.elements,function(e,i){if(!qq.isInput(i,!0)&&"textarea"!==i.tagName.toLowerCase()||!n(i.type)||o(i)){if("select"===i.tagName.toLowerCase()&&!o(i)){var a=r(i);null!==a&&(t[i.name]=a)}}else t[i.name]=i.value}),t}}),qq.traditional=qq.traditional||{},qq.traditional.FormUploadHandler=function(e,t){"use strict";function n(e,t){var n,i,r;try{i=t.contentDocument||t.contentWindow.document,r=i.body.innerHTML,s("converting iframe's innerHTML to JSON"),s("innerHTML = "+r),r&&r.match(/^= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\" \"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq*/\n/**\n * Upload handler used that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to\n * a generic server.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.traditional = qq.traditional || {};\nqq.traditional.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log;\n\n /**\n * Returns json object received by iframe from server.\n */\n function getIframeContentJson(id, iframe) {\n /*jshint evil: true*/\n\n var response, doc, innerHtml;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n log(\"converting iframe's innerHTML to JSON\");\n log(\"innerHTML = \" + innerHtml);\n //plain text response may be wrapped in tag\n if (innerHtml && innerHtml.match(/^ element styles */
+.qq-uploader DIALOG {
+ display: none;
+}
+
+.qq-uploader DIALOG[open] {
+ display: block;
+}
+
+.qq-uploader DIALOG {
+ display: none;
+}
+
+.qq-uploader DIALOG[open] {
+ display: block;
+}
+
+.qq-uploader DIALOG .qq-dialog-buttons {
+ text-align: center;
+ padding-top: 10px;
+}
+
+.qq-uploader DIALOG .qq-dialog-buttons BUTTON {
+ margin-left: 5px;
+ margin-right: 5px;
+}
+
+.qq-uploader DIALOG .qq-dialog-message-selector {
+ padding-bottom: 10px;
+}
+
+.qq-uploader DIALOG::backdrop {
+ background-color: rgba(0, 0, 0, 0.7);
+}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader.js b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.js
new file mode 100644
index 000000000000..04e3cc0733f5
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.js
@@ -0,0 +1,7414 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+(function(global) {
+ var qq = function(element) {
+ "use strict";
+ return {
+ hide: function() {
+ element.style.display = "none";
+ return this;
+ },
+ attach: function(type, fn) {
+ if (element.addEventListener) {
+ element.addEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.attachEvent("on" + type, fn);
+ }
+ return function() {
+ qq(element).detach(type, fn);
+ };
+ },
+ detach: function(type, fn) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, fn, false);
+ } else if (element.attachEvent) {
+ element.detachEvent("on" + type, fn);
+ }
+ return this;
+ },
+ contains: function(descendant) {
+ if (!descendant) {
+ return false;
+ }
+ if (element === descendant) {
+ return true;
+ }
+ if (element.contains) {
+ return element.contains(descendant);
+ } else {
+ return !!(descendant.compareDocumentPosition(element) & 8);
+ }
+ },
+ insertBefore: function(elementB) {
+ elementB.parentNode.insertBefore(element, elementB);
+ return this;
+ },
+ remove: function() {
+ element.parentNode.removeChild(element);
+ return this;
+ },
+ css: function(styles) {
+ if (element.style == null) {
+ throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");
+ }
+ if (styles.opacity != null) {
+ if (typeof element.style.opacity !== "string" && typeof element.filters !== "undefined") {
+ styles.filter = "alpha(opacity=" + Math.round(100 * styles.opacity) + ")";
+ }
+ }
+ qq.extend(element.style, styles);
+ return this;
+ },
+ hasClass: function(name, considerParent) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));
+ },
+ addClass: function(name) {
+ if (!qq(element).hasClass(name)) {
+ element.className += " " + name;
+ }
+ return this;
+ },
+ removeClass: function(name) {
+ var re = new RegExp("(^| )" + name + "( |$)");
+ element.className = element.className.replace(re, " ").replace(/^\s+|\s+$/g, "");
+ return this;
+ },
+ getByClass: function(className, first) {
+ var candidates, result = [];
+ if (first && element.querySelector) {
+ return element.querySelector("." + className);
+ } else if (element.querySelectorAll) {
+ return element.querySelectorAll("." + className);
+ }
+ candidates = element.getElementsByTagName("*");
+ qq.each(candidates, function(idx, val) {
+ if (qq(val).hasClass(className)) {
+ result.push(val);
+ }
+ });
+ return first ? result[0] : result;
+ },
+ getFirstByClass: function(className) {
+ return qq(element).getByClass(className, true);
+ },
+ children: function() {
+ var children = [], child = element.firstChild;
+ while (child) {
+ if (child.nodeType === 1) {
+ children.push(child);
+ }
+ child = child.nextSibling;
+ }
+ return children;
+ },
+ setText: function(text) {
+ element.innerText = text;
+ element.textContent = text;
+ return this;
+ },
+ clearText: function() {
+ return qq(element).setText("");
+ },
+ hasAttribute: function(attrName) {
+ var attrVal;
+ if (element.hasAttribute) {
+ if (!element.hasAttribute(attrName)) {
+ return false;
+ }
+ return /^false$/i.exec(element.getAttribute(attrName)) == null;
+ } else {
+ attrVal = element[attrName];
+ if (attrVal === undefined) {
+ return false;
+ }
+ return /^false$/i.exec(attrVal) == null;
+ }
+ }
+ };
+ };
+ (function() {
+ "use strict";
+ qq.canvasToBlob = function(canvas, mime, quality) {
+ return qq.dataUriToBlob(canvas.toDataURL(mime, quality));
+ };
+ qq.dataUriToBlob = function(dataUri) {
+ var arrayBuffer, byteString, createBlob = function(data, mime) {
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }, intArray, mimeString;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return createBlob(arrayBuffer, mimeString);
+ };
+ qq.log = function(message, level) {
+ if (window.console) {
+ if (!level || level === "info") {
+ window.console.log(message);
+ } else {
+ if (window.console[level]) {
+ window.console[level](message);
+ } else {
+ window.console.log("<" + level + "> " + message);
+ }
+ }
+ }
+ };
+ qq.isObject = function(variable) {
+ return variable && !variable.nodeType && Object.prototype.toString.call(variable) === "[object Object]";
+ };
+ qq.isFunction = function(variable) {
+ return typeof variable === "function";
+ };
+ qq.isArray = function(value) {
+ return Object.prototype.toString.call(value) === "[object Array]" || value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer;
+ };
+ qq.isItemList = function(maybeItemList) {
+ return Object.prototype.toString.call(maybeItemList) === "[object DataTransferItemList]";
+ };
+ qq.isNodeList = function(maybeNodeList) {
+ return Object.prototype.toString.call(maybeNodeList) === "[object NodeList]" || maybeNodeList.item && maybeNodeList.namedItem;
+ };
+ qq.isString = function(maybeString) {
+ return Object.prototype.toString.call(maybeString) === "[object String]";
+ };
+ qq.trimStr = function(string) {
+ if (String.prototype.trim) {
+ return string.trim();
+ }
+ return string.replace(/^\s+|\s+$/g, "");
+ };
+ qq.format = function(str) {
+ var args = Array.prototype.slice.call(arguments, 1), newStr = str, nextIdxToReplace = newStr.indexOf("{}");
+ qq.each(args, function(idx, val) {
+ var strBefore = newStr.substring(0, nextIdxToReplace), strAfter = newStr.substring(nextIdxToReplace + 2);
+ newStr = strBefore + val + strAfter;
+ nextIdxToReplace = newStr.indexOf("{}", nextIdxToReplace + val.length);
+ if (nextIdxToReplace < 0) {
+ return false;
+ }
+ });
+ return newStr;
+ };
+ qq.isFile = function(maybeFile) {
+ return window.File && Object.prototype.toString.call(maybeFile) === "[object File]";
+ };
+ qq.isFileList = function(maybeFileList) {
+ return window.FileList && Object.prototype.toString.call(maybeFileList) === "[object FileList]";
+ };
+ qq.isFileOrInput = function(maybeFileOrInput) {
+ return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);
+ };
+ qq.isInput = function(maybeInput, notFile) {
+ var evaluateType = function(type) {
+ var normalizedType = type.toLowerCase();
+ if (notFile) {
+ return normalizedType !== "file";
+ }
+ return normalizedType === "file";
+ };
+ if (window.HTMLInputElement) {
+ if (Object.prototype.toString.call(maybeInput) === "[object HTMLInputElement]") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ if (maybeInput.tagName) {
+ if (maybeInput.tagName.toLowerCase() === "input") {
+ if (maybeInput.type && evaluateType(maybeInput.type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ qq.isBlob = function(maybeBlob) {
+ if (window.Blob && Object.prototype.toString.call(maybeBlob) === "[object Blob]") {
+ return true;
+ }
+ };
+ qq.isXhrUploadSupported = function() {
+ var input = document.createElement("input");
+ input.type = "file";
+ return input.multiple !== undefined && typeof File !== "undefined" && typeof FormData !== "undefined" && typeof qq.createXhrInstance().upload !== "undefined";
+ };
+ qq.createXhrInstance = function() {
+ if (window.XMLHttpRequest) {
+ return new XMLHttpRequest();
+ }
+ try {
+ return new ActiveXObject("MSXML2.XMLHTTP.3.0");
+ } catch (error) {
+ qq.log("Neither XHR or ActiveX are supported!", "error");
+ return null;
+ }
+ };
+ qq.isFolderDropSupported = function(dataTransfer) {
+ return dataTransfer.items && dataTransfer.items.length > 0 && dataTransfer.items[0].webkitGetAsEntry;
+ };
+ qq.isFileChunkingSupported = function() {
+ return !qq.androidStock() && qq.isXhrUploadSupported() && (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);
+ };
+ qq.sliceBlob = function(fileOrBlob, start, end) {
+ var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;
+ return slicer.call(fileOrBlob, start, end);
+ };
+ qq.arrayBufferToHex = function(buffer) {
+ var bytesAsHex = "", bytes = new Uint8Array(buffer);
+ qq.each(bytes, function(idx, byt) {
+ var byteAsHexStr = byt.toString(16);
+ if (byteAsHexStr.length < 2) {
+ byteAsHexStr = "0" + byteAsHexStr;
+ }
+ bytesAsHex += byteAsHexStr;
+ });
+ return bytesAsHex;
+ };
+ qq.readBlobToHex = function(blob, startOffset, length) {
+ var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), fileReader = new FileReader(), promise = new qq.Promise();
+ fileReader.onload = function() {
+ promise.success(qq.arrayBufferToHex(fileReader.result));
+ };
+ fileReader.onerror = promise.failure;
+ fileReader.readAsArrayBuffer(initialBlob);
+ return promise;
+ };
+ qq.extend = function(first, second, extendNested) {
+ qq.each(second, function(prop, val) {
+ if (extendNested && qq.isObject(val)) {
+ if (first[prop] === undefined) {
+ first[prop] = {};
+ }
+ qq.extend(first[prop], val, true);
+ } else {
+ first[prop] = val;
+ }
+ });
+ return first;
+ };
+ qq.override = function(target, sourceFn) {
+ var super_ = {}, source = sourceFn(super_);
+ qq.each(source, function(srcPropName, srcPropVal) {
+ if (target[srcPropName] !== undefined) {
+ super_[srcPropName] = target[srcPropName];
+ }
+ target[srcPropName] = srcPropVal;
+ });
+ return target;
+ };
+ qq.indexOf = function(arr, elt, from) {
+ if (arr.indexOf) {
+ return arr.indexOf(elt, from);
+ }
+ from = from || 0;
+ var len = arr.length;
+ if (from < 0) {
+ from += len;
+ }
+ for (;from < len; from += 1) {
+ if (arr.hasOwnProperty(from) && arr[from] === elt) {
+ return from;
+ }
+ }
+ return -1;
+ };
+ qq.getUniqueId = function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
+ return v.toString(16);
+ });
+ };
+ qq.ie = function() {
+ return navigator.userAgent.indexOf("MSIE") !== -1 || navigator.userAgent.indexOf("Trident") !== -1;
+ };
+ qq.ie7 = function() {
+ return navigator.userAgent.indexOf("MSIE 7") !== -1;
+ };
+ qq.ie8 = function() {
+ return navigator.userAgent.indexOf("MSIE 8") !== -1;
+ };
+ qq.ie10 = function() {
+ return navigator.userAgent.indexOf("MSIE 10") !== -1;
+ };
+ qq.ie11 = function() {
+ return qq.ie() && navigator.userAgent.indexOf("rv:11") !== -1;
+ };
+ qq.edge = function() {
+ return navigator.userAgent.indexOf("Edge") >= 0;
+ };
+ qq.safari = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Apple") !== -1;
+ };
+ qq.chrome = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Google") !== -1;
+ };
+ qq.opera = function() {
+ return navigator.vendor !== undefined && navigator.vendor.indexOf("Opera") !== -1;
+ };
+ qq.firefox = function() {
+ return !qq.edge() && !qq.ie11() && navigator.userAgent.indexOf("Mozilla") !== -1 && navigator.vendor !== undefined && navigator.vendor === "";
+ };
+ qq.windows = function() {
+ return navigator.platform === "Win32";
+ };
+ qq.android = function() {
+ return navigator.userAgent.toLowerCase().indexOf("android") !== -1;
+ };
+ qq.androidStock = function() {
+ return qq.android() && navigator.userAgent.toLowerCase().indexOf("chrome") < 0;
+ };
+ qq.ios6 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 6_") !== -1;
+ };
+ qq.ios7 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 7_") !== -1;
+ };
+ qq.ios8 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_") !== -1;
+ };
+ qq.ios800 = function() {
+ return qq.ios() && navigator.userAgent.indexOf(" OS 8_0 ") !== -1;
+ };
+ qq.ios = function() {
+ return navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("iPod") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1;
+ };
+ qq.iosChrome = function() {
+ return qq.ios() && navigator.userAgent.indexOf("CriOS") !== -1;
+ };
+ qq.iosSafari = function() {
+ return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf("Safari") !== -1;
+ };
+ qq.iosSafariWebView = function() {
+ return qq.ios() && !qq.iosChrome() && !qq.iosSafari();
+ };
+ qq.preventDefault = function(e) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ };
+ qq.toElement = function() {
+ var div = document.createElement("div");
+ return function(html) {
+ div.innerHTML = html;
+ var element = div.firstChild;
+ div.removeChild(element);
+ return element;
+ };
+ }();
+ qq.each = function(iterableItem, callback) {
+ var keyOrIndex, retVal;
+ if (iterableItem) {
+ if (window.Storage && iterableItem.constructor === window.Storage) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else if (qq.isString(iterableItem)) {
+ for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {
+ retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));
+ if (retVal === false) {
+ break;
+ }
+ }
+ } else {
+ for (keyOrIndex in iterableItem) {
+ if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {
+ retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);
+ if (retVal === false) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ };
+ qq.bind = function(oldFunc, context) {
+ if (qq.isFunction(oldFunc)) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ return function() {
+ var newArgs = qq.extend([], args);
+ if (arguments.length) {
+ newArgs = newArgs.concat(Array.prototype.slice.call(arguments));
+ }
+ return oldFunc.apply(context, newArgs);
+ };
+ }
+ throw new Error("first parameter must be a function!");
+ };
+ qq.obj2url = function(obj, temp, prefixDone) {
+ var uristrings = [], prefix = "&", add = function(nextObj, i) {
+ var nextTemp = temp ? /\[\]$/.test(temp) ? temp : temp + "[" + i + "]" : i;
+ if (nextTemp !== "undefined" && i !== "undefined") {
+ uristrings.push(typeof nextObj === "object" ? qq.obj2url(nextObj, nextTemp, true) : Object.prototype.toString.call(nextObj) === "[object Function]" ? encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj));
+ }
+ };
+ if (!prefixDone && temp) {
+ prefix = /\?/.test(temp) ? /\?$/.test(temp) ? "" : "&" : "?";
+ uristrings.push(temp);
+ uristrings.push(qq.obj2url(obj));
+ } else if (Object.prototype.toString.call(obj) === "[object Array]" && typeof obj !== "undefined") {
+ qq.each(obj, function(idx, val) {
+ add(val, idx);
+ });
+ } else if (typeof obj !== "undefined" && obj !== null && typeof obj === "object") {
+ qq.each(obj, function(prop, val) {
+ add(val, prop);
+ });
+ } else {
+ uristrings.push(encodeURIComponent(temp) + "=" + encodeURIComponent(obj));
+ }
+ if (temp) {
+ return uristrings.join(prefix);
+ } else {
+ return uristrings.join(prefix).replace(/^&/, "").replace(/%20/g, "+");
+ }
+ };
+ qq.obj2FormData = function(obj, formData, arrayKeyName) {
+ if (!formData) {
+ formData = new FormData();
+ }
+ qq.each(obj, function(key, val) {
+ key = arrayKeyName ? arrayKeyName + "[" + key + "]" : key;
+ if (qq.isObject(val)) {
+ qq.obj2FormData(val, formData, key);
+ } else if (qq.isFunction(val)) {
+ formData.append(key, val());
+ } else {
+ formData.append(key, val);
+ }
+ });
+ return formData;
+ };
+ qq.obj2Inputs = function(obj, form) {
+ var input;
+ if (!form) {
+ form = document.createElement("form");
+ }
+ qq.obj2FormData(obj, {
+ append: function(key, val) {
+ input = document.createElement("input");
+ input.setAttribute("name", key);
+ input.setAttribute("value", val);
+ form.appendChild(input);
+ }
+ });
+ return form;
+ };
+ qq.parseJson = function(json) {
+ if (window.JSON && qq.isFunction(JSON.parse)) {
+ return JSON.parse(json);
+ } else {
+ return eval("(" + json + ")");
+ }
+ };
+ qq.getExtension = function(filename) {
+ var extIdx = filename.lastIndexOf(".") + 1;
+ if (extIdx > 0) {
+ return filename.substr(extIdx, filename.length - extIdx);
+ }
+ };
+ qq.getFilename = function(blobOrFileInput) {
+ if (qq.isInput(blobOrFileInput)) {
+ return blobOrFileInput.value.replace(/.*(\/|\\)/, "");
+ } else if (qq.isFile(blobOrFileInput)) {
+ if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {
+ return blobOrFileInput.fileName;
+ }
+ }
+ return blobOrFileInput.name;
+ };
+ qq.DisposeSupport = function() {
+ var disposers = [];
+ return {
+ dispose: function() {
+ var disposer;
+ do {
+ disposer = disposers.shift();
+ if (disposer) {
+ disposer();
+ }
+ } while (disposer);
+ },
+ attach: function() {
+ var args = arguments;
+ this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));
+ },
+ addDisposer: function(disposeFunction) {
+ disposers.push(disposeFunction);
+ }
+ };
+ };
+ })();
+ (function() {
+ "use strict";
+ if (typeof define === "function" && define.amd) {
+ define(function() {
+ return qq;
+ });
+ } else if (typeof module !== "undefined" && module.exports) {
+ module.exports = qq;
+ } else {
+ global.qq = qq;
+ }
+ })();
+ (function() {
+ "use strict";
+ qq.Error = function(message) {
+ this.message = "[Fine Uploader " + qq.version + "] " + message;
+ };
+ qq.Error.prototype = new Error();
+ })();
+ qq.version = "5.13.0";
+ qq.supportedFeatures = function() {
+ "use strict";
+ var supportsUploading, supportsUploadingBlobs, supportsFileDrop, supportsAjaxFileUploading, supportsFolderDrop, supportsChunking, supportsResume, supportsUploadViaPaste, supportsUploadCors, supportsDeleteFileXdr, supportsDeleteFileCorsXhr, supportsDeleteFileCors, supportsFolderSelection, supportsImagePreviews, supportsUploadProgress;
+ function testSupportsFileInputElement() {
+ var supported = true, tempInput;
+ try {
+ tempInput = document.createElement("input");
+ tempInput.type = "file";
+ qq(tempInput).hide();
+ if (tempInput.disabled) {
+ supported = false;
+ }
+ } catch (ex) {
+ supported = false;
+ }
+ return supported;
+ }
+ function isChrome21OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[2][1-9]|Chrome\/[3-9][0-9]/) !== undefined;
+ }
+ function isChrome14OrHigher() {
+ return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/) !== undefined;
+ }
+ function isCrossOriginXhrSupported() {
+ if (window.XMLHttpRequest) {
+ var xhr = qq.createXhrInstance();
+ return xhr.withCredentials !== undefined;
+ }
+ return false;
+ }
+ function isXdrSupported() {
+ return window.XDomainRequest !== undefined;
+ }
+ function isCrossOriginAjaxSupported() {
+ if (isCrossOriginXhrSupported()) {
+ return true;
+ }
+ return isXdrSupported();
+ }
+ function isFolderSelectionSupported() {
+ return document.createElement("input").webkitdirectory !== undefined;
+ }
+ function isLocalStorageSupported() {
+ try {
+ return !!window.localStorage && qq.isFunction(window.localStorage.setItem);
+ } catch (error) {
+ return false;
+ }
+ }
+ function isDragAndDropSupported() {
+ var span = document.createElement("span");
+ return ("draggable" in span || "ondragstart" in span && "ondrop" in span) && !qq.android() && !qq.ios();
+ }
+ supportsUploading = testSupportsFileInputElement();
+ supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();
+ supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();
+ supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();
+ supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();
+ supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();
+ supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();
+ supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();
+ supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);
+ supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();
+ supportsDeleteFileXdr = isXdrSupported();
+ supportsDeleteFileCors = isCrossOriginAjaxSupported();
+ supportsFolderSelection = isFolderSelectionSupported();
+ supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;
+ supportsUploadProgress = function() {
+ if (supportsAjaxFileUploading) {
+ return !qq.androidStock() && !qq.iosChrome();
+ }
+ return false;
+ }();
+ return {
+ ajaxUploading: supportsAjaxFileUploading,
+ blobUploading: supportsUploadingBlobs,
+ canDetermineSize: supportsAjaxFileUploading,
+ chunking: supportsChunking,
+ deleteFileCors: supportsDeleteFileCors,
+ deleteFileCorsXdr: supportsDeleteFileXdr,
+ deleteFileCorsXhr: supportsDeleteFileCorsXhr,
+ dialogElement: !!window.HTMLDialogElement,
+ fileDrop: supportsFileDrop,
+ folderDrop: supportsFolderDrop,
+ folderSelection: supportsFolderSelection,
+ imagePreviews: supportsImagePreviews,
+ imageValidation: supportsImagePreviews,
+ itemSizeValidation: supportsAjaxFileUploading,
+ pause: supportsChunking,
+ progressBar: supportsUploadProgress,
+ resume: supportsResume,
+ scaling: supportsImagePreviews && supportsUploadingBlobs,
+ tiffPreviews: qq.safari(),
+ unlimitedScaledImageSize: !qq.ios(),
+ uploading: supportsUploading,
+ uploadCors: supportsUploadCors,
+ uploadCustomHeaders: supportsAjaxFileUploading,
+ uploadNonMultipart: supportsAjaxFileUploading,
+ uploadViaPaste: supportsUploadViaPaste
+ };
+ }();
+ qq.isGenericPromise = function(maybePromise) {
+ "use strict";
+ return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));
+ };
+ qq.Promise = function() {
+ "use strict";
+ var successArgs, failureArgs, successCallbacks = [], failureCallbacks = [], doneCallbacks = [], state = 0;
+ qq.extend(this, {
+ then: function(onSuccess, onFailure) {
+ if (state === 0) {
+ if (onSuccess) {
+ successCallbacks.push(onSuccess);
+ }
+ if (onFailure) {
+ failureCallbacks.push(onFailure);
+ }
+ } else if (state === -1) {
+ onFailure && onFailure.apply(null, failureArgs);
+ } else if (onSuccess) {
+ onSuccess.apply(null, successArgs);
+ }
+ return this;
+ },
+ done: function(callback) {
+ if (state === 0) {
+ doneCallbacks.push(callback);
+ } else {
+ callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);
+ }
+ return this;
+ },
+ success: function() {
+ state = 1;
+ successArgs = arguments;
+ if (successCallbacks.length) {
+ qq.each(successCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, successArgs);
+ });
+ }
+ return this;
+ },
+ failure: function() {
+ state = -1;
+ failureArgs = arguments;
+ if (failureCallbacks.length) {
+ qq.each(failureCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ if (doneCallbacks.length) {
+ qq.each(doneCallbacks, function(idx, callback) {
+ callback.apply(null, failureArgs);
+ });
+ }
+ return this;
+ }
+ });
+ };
+ qq.BlobProxy = function(referenceBlob, onCreate) {
+ "use strict";
+ qq.extend(this, {
+ referenceBlob: referenceBlob,
+ create: function() {
+ return onCreate(referenceBlob);
+ }
+ });
+ };
+ qq.UploadButton = function(o) {
+ "use strict";
+ var self = this, disposeSupport = new qq.DisposeSupport(), options = {
+ acceptFiles: null,
+ element: null,
+ focusClass: "qq-upload-button-focus",
+ folders: false,
+ hoverClass: "qq-upload-button-hover",
+ ios8BrowserCrashWorkaround: false,
+ multiple: false,
+ name: "qqfile",
+ onChange: function(input) {},
+ title: null
+ }, input, buttonId;
+ qq.extend(options, o);
+ buttonId = qq.getUniqueId();
+ function createInput() {
+ var input = document.createElement("input");
+ input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);
+ input.setAttribute("title", options.title);
+ self.setMultiple(options.multiple, input);
+ if (options.folders && qq.supportedFeatures.folderSelection) {
+ input.setAttribute("webkitdirectory", "");
+ }
+ if (options.acceptFiles) {
+ input.setAttribute("accept", options.acceptFiles);
+ }
+ input.setAttribute("type", "file");
+ input.setAttribute("name", options.name);
+ qq(input).css({
+ position: "absolute",
+ right: 0,
+ top: 0,
+ fontFamily: "Arial",
+ fontSize: qq.ie() && !qq.ie8() ? "3500px" : "118px",
+ margin: 0,
+ padding: 0,
+ cursor: "pointer",
+ opacity: 0
+ });
+ !qq.ie7() && qq(input).css({
+ height: "100%"
+ });
+ options.element.appendChild(input);
+ disposeSupport.attach(input, "change", function() {
+ options.onChange(input);
+ });
+ disposeSupport.attach(input, "mouseover", function() {
+ qq(options.element).addClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "mouseout", function() {
+ qq(options.element).removeClass(options.hoverClass);
+ });
+ disposeSupport.attach(input, "focus", function() {
+ qq(options.element).addClass(options.focusClass);
+ });
+ disposeSupport.attach(input, "blur", function() {
+ qq(options.element).removeClass(options.focusClass);
+ });
+ return input;
+ }
+ qq(options.element).css({
+ position: "relative",
+ overflow: "hidden",
+ direction: "ltr"
+ });
+ qq.extend(this, {
+ getInput: function() {
+ return input;
+ },
+ getButtonId: function() {
+ return buttonId;
+ },
+ setMultiple: function(isMultiple, optInput) {
+ var input = optInput || this.getInput();
+ if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {
+ input.setAttribute("multiple", "");
+ } else {
+ if (isMultiple) {
+ input.setAttribute("multiple", "");
+ } else {
+ input.removeAttribute("multiple");
+ }
+ }
+ },
+ setAcceptFiles: function(acceptFiles) {
+ if (acceptFiles !== options.acceptFiles) {
+ input.setAttribute("accept", acceptFiles);
+ }
+ },
+ reset: function() {
+ if (input.parentNode) {
+ qq(input).remove();
+ }
+ qq(options.element).removeClass(options.focusClass);
+ input = null;
+ input = createInput();
+ }
+ });
+ input = createInput();
+ };
+ qq.UploadButton.BUTTON_ID_ATTR_NAME = "qq-button-id";
+ qq.UploadData = function(uploaderProxy) {
+ "use strict";
+ var data = [], byUuid = {}, byStatus = {}, byProxyGroupId = {}, byBatchId = {};
+ function getDataByIds(idOrIds) {
+ if (qq.isArray(idOrIds)) {
+ var entries = [];
+ qq.each(idOrIds, function(idx, id) {
+ entries.push(data[id]);
+ });
+ return entries;
+ }
+ return data[idOrIds];
+ }
+ function getDataByUuids(uuids) {
+ if (qq.isArray(uuids)) {
+ var entries = [];
+ qq.each(uuids, function(idx, uuid) {
+ entries.push(data[byUuid[uuid]]);
+ });
+ return entries;
+ }
+ return data[byUuid[uuids]];
+ }
+ function getDataByStatus(status) {
+ var statusResults = [], statuses = [].concat(status);
+ qq.each(statuses, function(index, statusEnum) {
+ var statusResultIndexes = byStatus[statusEnum];
+ if (statusResultIndexes !== undefined) {
+ qq.each(statusResultIndexes, function(i, dataIndex) {
+ statusResults.push(data[dataIndex]);
+ });
+ }
+ });
+ return statusResults;
+ }
+ qq.extend(this, {
+ addFile: function(spec) {
+ var status = spec.status || qq.status.SUBMITTING, id = data.push({
+ name: spec.name,
+ originalName: spec.name,
+ uuid: spec.uuid,
+ size: spec.size == null ? -1 : spec.size,
+ status: status
+ }) - 1;
+ if (spec.batchId) {
+ data[id].batchId = spec.batchId;
+ if (byBatchId[spec.batchId] === undefined) {
+ byBatchId[spec.batchId] = [];
+ }
+ byBatchId[spec.batchId].push(id);
+ }
+ if (spec.proxyGroupId) {
+ data[id].proxyGroupId = spec.proxyGroupId;
+ if (byProxyGroupId[spec.proxyGroupId] === undefined) {
+ byProxyGroupId[spec.proxyGroupId] = [];
+ }
+ byProxyGroupId[spec.proxyGroupId].push(id);
+ }
+ data[id].id = id;
+ byUuid[spec.uuid] = id;
+ if (byStatus[status] === undefined) {
+ byStatus[status] = [];
+ }
+ byStatus[status].push(id);
+ uploaderProxy.onStatusChange(id, null, status);
+ return id;
+ },
+ retrieve: function(optionalFilter) {
+ if (qq.isObject(optionalFilter) && data.length) {
+ if (optionalFilter.id !== undefined) {
+ return getDataByIds(optionalFilter.id);
+ } else if (optionalFilter.uuid !== undefined) {
+ return getDataByUuids(optionalFilter.uuid);
+ } else if (optionalFilter.status) {
+ return getDataByStatus(optionalFilter.status);
+ }
+ } else {
+ return qq.extend([], data, true);
+ }
+ },
+ reset: function() {
+ data = [];
+ byUuid = {};
+ byStatus = {};
+ byBatchId = {};
+ },
+ setStatus: function(id, newStatus) {
+ var oldStatus = data[id].status, byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);
+ byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);
+ data[id].status = newStatus;
+ if (byStatus[newStatus] === undefined) {
+ byStatus[newStatus] = [];
+ }
+ byStatus[newStatus].push(id);
+ uploaderProxy.onStatusChange(id, oldStatus, newStatus);
+ },
+ uuidChanged: function(id, newUuid) {
+ var oldUuid = data[id].uuid;
+ data[id].uuid = newUuid;
+ byUuid[newUuid] = id;
+ delete byUuid[oldUuid];
+ },
+ updateName: function(id, newName) {
+ data[id].name = newName;
+ },
+ updateSize: function(id, newSize) {
+ data[id].size = newSize;
+ },
+ setParentId: function(targetId, parentId) {
+ data[targetId].parentId = parentId;
+ },
+ getIdsInProxyGroup: function(id) {
+ var proxyGroupId = data[id].proxyGroupId;
+ if (proxyGroupId) {
+ return byProxyGroupId[proxyGroupId];
+ }
+ return [];
+ },
+ getIdsInBatch: function(id) {
+ var batchId = data[id].batchId;
+ return byBatchId[batchId];
+ }
+ });
+ };
+ qq.status = {
+ SUBMITTING: "submitting",
+ SUBMITTED: "submitted",
+ REJECTED: "rejected",
+ QUEUED: "queued",
+ CANCELED: "canceled",
+ PAUSED: "paused",
+ UPLOADING: "uploading",
+ UPLOAD_RETRYING: "retrying upload",
+ UPLOAD_SUCCESSFUL: "upload successful",
+ UPLOAD_FAILED: "upload failed",
+ DELETE_FAILED: "delete failed",
+ DELETING: "deleting",
+ DELETED: "deleted"
+ };
+ (function() {
+ "use strict";
+ qq.basePublicApi = {
+ addBlobs: function(blobDataOrArray, params, endpoint) {
+ this.addFiles(blobDataOrArray, params, endpoint);
+ },
+ addInitialFiles: function(cannedFileList) {
+ var self = this;
+ qq.each(cannedFileList, function(index, cannedFile) {
+ self._addCannedFile(cannedFile);
+ });
+ },
+ addFiles: function(data, params, endpoint) {
+ this._maybeHandleIos8SafariWorkaround();
+ var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId, processBlob = qq.bind(function(blob) {
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName
+ }, batchId, verifiedFiles);
+ }, this), processBlobData = qq.bind(function(blobData) {
+ this._handleNewFile(blobData, batchId, verifiedFiles);
+ }, this), processCanvas = qq.bind(function(canvas) {
+ var blob = qq.canvasToBlob(canvas);
+ this._handleNewFile({
+ blob: blob,
+ name: this._options.blobs.defaultName + ".png"
+ }, batchId, verifiedFiles);
+ }, this), processCanvasData = qq.bind(function(canvasData) {
+ var normalizedQuality = canvasData.quality && canvasData.quality / 100, blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);
+ this._handleNewFile({
+ blob: blob,
+ name: canvasData.name
+ }, batchId, verifiedFiles);
+ }, this), processFileOrInput = qq.bind(function(fileOrInput) {
+ if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {
+ var files = Array.prototype.slice.call(fileOrInput.files), self = this;
+ qq.each(files, function(idx, file) {
+ self._handleNewFile(file, batchId, verifiedFiles);
+ });
+ } else {
+ this._handleNewFile(fileOrInput, batchId, verifiedFiles);
+ }
+ }, this), normalizeData = function() {
+ if (qq.isFileList(data)) {
+ data = Array.prototype.slice.call(data);
+ }
+ data = [].concat(data);
+ }, self = this, verifiedFiles = [];
+ this._currentBatchId = batchId;
+ if (data) {
+ normalizeData();
+ qq.each(data, function(idx, fileContainer) {
+ if (qq.isFileOrInput(fileContainer)) {
+ processFileOrInput(fileContainer);
+ } else if (qq.isBlob(fileContainer)) {
+ processBlob(fileContainer);
+ } else if (qq.isObject(fileContainer)) {
+ if (fileContainer.blob && fileContainer.name) {
+ processBlobData(fileContainer);
+ } else if (fileContainer.canvas && fileContainer.name) {
+ processCanvasData(fileContainer);
+ }
+ } else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === "canvas") {
+ processCanvas(fileContainer);
+ } else {
+ self.log(fileContainer + " is not a valid file container! Ignoring!", "warn");
+ }
+ });
+ this.log("Received " + verifiedFiles.length + " files.");
+ this._prepareItemsForUpload(verifiedFiles, params, endpoint);
+ }
+ },
+ cancel: function(id) {
+ this._handler.cancel(id);
+ },
+ cancelAll: function() {
+ var storedIdsCopy = [], self = this;
+ qq.extend(storedIdsCopy, this._storedIds);
+ qq.each(storedIdsCopy, function(idx, storedFileId) {
+ self.cancel(storedFileId);
+ });
+ this._handler.cancelAll();
+ },
+ clearStoredFiles: function() {
+ this._storedIds = [];
+ },
+ continueUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (uploadData.status === qq.status.PAUSED) {
+ this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.", id, this.getName(id)));
+ this._uploadFile(id);
+ return true;
+ } else {
+ this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ deleteFile: function(id) {
+ return this._onSubmitDelete(id);
+ },
+ doesExist: function(fileOrBlobId) {
+ return this._handler.isValid(fileOrBlobId);
+ },
+ drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {
+ var promiseToReturn = new qq.Promise(), fileOrUrl, options;
+ if (this._imageGenerator) {
+ fileOrUrl = this._thumbnailUrls[fileId];
+ options = {
+ customResizeFunction: customResizeFunction,
+ maxSize: maxSize > 0 ? maxSize : null,
+ scale: maxSize > 0
+ };
+ if (!fromServer && qq.supportedFeatures.imagePreviews) {
+ fileOrUrl = this.getFile(fileId);
+ }
+ if (fileOrUrl == null) {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "File or URL not found."
+ });
+ } else {
+ this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(function success(modifiedContainer) {
+ promiseToReturn.success(modifiedContainer);
+ }, function failure(container, reason) {
+ promiseToReturn.failure({
+ container: container,
+ error: reason || "Problem generating thumbnail"
+ });
+ });
+ }
+ } else {
+ promiseToReturn.failure({
+ container: imgOrCanvas,
+ error: "Missing image generator module"
+ });
+ }
+ return promiseToReturn;
+ },
+ getButton: function(fileId) {
+ return this._getButton(this._buttonIdsForFileIds[fileId]);
+ },
+ getEndpoint: function(fileId) {
+ return this._endpointStore.get(fileId);
+ },
+ getFile: function(fileOrBlobId) {
+ return this._handler.getFile(fileOrBlobId) || null;
+ },
+ getInProgress: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED ]
+ }).length;
+ },
+ getName: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).name;
+ },
+ getParentId: function(id) {
+ var uploadDataEntry = this.getUploads({
+ id: id
+ }), parentId = null;
+ if (uploadDataEntry) {
+ if (uploadDataEntry.parentId !== undefined) {
+ parentId = uploadDataEntry.parentId;
+ }
+ }
+ return parentId;
+ },
+ getResumableFilesData: function() {
+ return this._handler.getResumableFilesData();
+ },
+ getSize: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).size;
+ },
+ getNetUploads: function() {
+ return this._netUploaded;
+ },
+ getRemainingAllowedItems: function() {
+ var allowedItems = this._currentItemLimit;
+ if (allowedItems > 0) {
+ return allowedItems - this._netUploadedOrQueued;
+ }
+ return null;
+ },
+ getUploads: function(optionalFilter) {
+ return this._uploadData.retrieve(optionalFilter);
+ },
+ getUuid: function(id) {
+ return this._uploadData.retrieve({
+ id: id
+ }).uuid;
+ },
+ log: function(str, level) {
+ if (this._options.debug && (!level || level === "info")) {
+ qq.log("[Fine Uploader " + qq.version + "] " + str);
+ } else if (level && level !== "info") {
+ qq.log("[Fine Uploader " + qq.version + "] " + str, level);
+ }
+ },
+ pauseUpload: function(id) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {
+ return false;
+ }
+ if (qq.indexOf([ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING ], uploadData.status) >= 0) {
+ if (this._handler.pause(id)) {
+ this._uploadData.setStatus(id, qq.status.PAUSED);
+ return true;
+ } else {
+ this.log(qq.format("Unable to pause file ID {} ({}).", id, this.getName(id)), "error");
+ }
+ } else {
+ this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.", id, this.getName(id)), "error");
+ }
+ return false;
+ },
+ reset: function() {
+ this.log("Resetting uploader...");
+ this._handler.reset();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ this._paramsStore.reset();
+ this._endpointStore.reset();
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData.reset();
+ this._buttonIdsForFileIds = [];
+ this._pasteHandler && this._pasteHandler.reset();
+ this._options.session.refreshOnReset && this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._totalProgress && this._totalProgress.reset();
+ },
+ retry: function(id) {
+ return this._manualRetry(id);
+ },
+ scaleImage: function(id, specs) {
+ var self = this;
+ return qq.Scaler.prototype.scaleImage(id, specs, {
+ log: qq.bind(self.log, self),
+ getFile: qq.bind(self.getFile, self),
+ uploadData: self._uploadData
+ });
+ },
+ setCustomHeaders: function(headers, id) {
+ this._customHeadersStore.set(headers, id);
+ },
+ setDeleteFileCustomHeaders: function(headers, id) {
+ this._deleteFileCustomHeadersStore.set(headers, id);
+ },
+ setDeleteFileEndpoint: function(endpoint, id) {
+ this._deleteFileEndpointStore.set(endpoint, id);
+ },
+ setDeleteFileParams: function(params, id) {
+ this._deleteFileParamsStore.set(params, id);
+ },
+ setEndpoint: function(endpoint, id) {
+ this._endpointStore.set(endpoint, id);
+ },
+ setForm: function(elementOrId) {
+ this._updateFormSupportAndParams(elementOrId);
+ },
+ setItemLimit: function(newItemLimit) {
+ this._currentItemLimit = newItemLimit;
+ },
+ setName: function(id, newName) {
+ this._uploadData.updateName(id, newName);
+ },
+ setParams: function(params, id) {
+ this._paramsStore.set(params, id);
+ },
+ setUuid: function(id, newUuid) {
+ return this._uploadData.uuidChanged(id, newUuid);
+ },
+ uploadStoredFiles: function() {
+ if (this._storedIds.length === 0) {
+ this._itemError("noFilesError");
+ } else {
+ this._uploadStoredFiles();
+ }
+ }
+ };
+ qq.basePrivateApi = {
+ _addCannedFile: function(sessionData) {
+ var id = this._uploadData.addFile({
+ uuid: sessionData.uuid,
+ name: sessionData.name,
+ size: sessionData.size,
+ status: qq.status.UPLOAD_SUCCESSFUL
+ });
+ sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);
+ sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);
+ if (sessionData.thumbnailUrl) {
+ this._thumbnailUrls[id] = sessionData.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._netUploadedOrQueued++;
+ return id;
+ },
+ _annotateWithButtonId: function(file, associatedInput) {
+ if (qq.isFile(file)) {
+ file.qqButtonId = this._getButtonId(associatedInput);
+ }
+ },
+ _batchError: function(message) {
+ this._options.callbacks.onError(null, null, message, undefined);
+ },
+ _createDeleteHandler: function() {
+ var self = this;
+ return new qq.DeleteFileAjaxRequester({
+ method: this._options.deleteFile.method.toUpperCase(),
+ maxConnections: this._options.maxConnections,
+ uuidParamName: this._options.request.uuidName,
+ customHeaders: this._deleteFileCustomHeadersStore,
+ paramsStore: this._deleteFileParamsStore,
+ endpointStore: this._deleteFileEndpointStore,
+ cors: this._options.cors,
+ log: qq.bind(self.log, self),
+ onDelete: function(id) {
+ self._onDelete(id);
+ self._options.callbacks.onDelete(id);
+ },
+ onDeleteComplete: function(id, xhrOrXdr, isError) {
+ self._onDeleteComplete(id, xhrOrXdr, isError);
+ self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);
+ }
+ });
+ },
+ _createPasteHandler: function() {
+ var self = this;
+ return new qq.PasteSupport({
+ targetElement: this._options.paste.targetElement,
+ callbacks: {
+ log: qq.bind(self.log, self),
+ pasteReceived: function(blob) {
+ self._handleCheckedCallback({
+ name: "onPasteReceived",
+ callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),
+ onSuccess: qq.bind(self._handlePasteSuccess, self, blob),
+ identifier: "pasted image"
+ });
+ }
+ }
+ });
+ },
+ _createStore: function(initialValue, _readOnlyValues_) {
+ var store = {}, catchall = initialValue, perIdReadOnlyValues = {}, readOnlyValues = _readOnlyValues_, copy = function(orig) {
+ if (qq.isObject(orig)) {
+ return qq.extend({}, orig);
+ }
+ return orig;
+ }, getReadOnlyValues = function() {
+ if (qq.isFunction(readOnlyValues)) {
+ return readOnlyValues();
+ }
+ return readOnlyValues;
+ }, includeReadOnlyValues = function(id, existing) {
+ if (readOnlyValues && qq.isObject(existing)) {
+ qq.extend(existing, getReadOnlyValues());
+ }
+ if (perIdReadOnlyValues[id]) {
+ qq.extend(existing, perIdReadOnlyValues[id]);
+ }
+ };
+ return {
+ set: function(val, id) {
+ if (id == null) {
+ store = {};
+ catchall = copy(val);
+ } else {
+ store[id] = copy(val);
+ }
+ },
+ get: function(id) {
+ var values;
+ if (id != null && store[id]) {
+ values = store[id];
+ } else {
+ values = copy(catchall);
+ }
+ includeReadOnlyValues(id, values);
+ return copy(values);
+ },
+ addReadOnly: function(id, values) {
+ if (qq.isObject(store)) {
+ if (id === null) {
+ if (qq.isFunction(values)) {
+ readOnlyValues = values;
+ } else {
+ readOnlyValues = readOnlyValues || {};
+ qq.extend(readOnlyValues, values);
+ }
+ } else {
+ perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};
+ qq.extend(perIdReadOnlyValues[id], values);
+ }
+ }
+ },
+ remove: function(fileId) {
+ return delete store[fileId];
+ },
+ reset: function() {
+ store = {};
+ perIdReadOnlyValues = {};
+ catchall = initialValue;
+ }
+ };
+ },
+ _createUploadDataTracker: function() {
+ var self = this;
+ return new qq.UploadData({
+ getName: function(id) {
+ return self.getName(id);
+ },
+ getUuid: function(id) {
+ return self.getUuid(id);
+ },
+ getSize: function(id) {
+ return self.getSize(id);
+ },
+ onStatusChange: function(id, oldStatus, newStatus) {
+ self._onUploadStatusChange(id, oldStatus, newStatus);
+ self._options.callbacks.onStatusChange(id, oldStatus, newStatus);
+ self._maybeAllComplete(id, newStatus);
+ if (self._totalProgress) {
+ setTimeout(function() {
+ self._totalProgress.onStatusChange(id, oldStatus, newStatus);
+ }, 0);
+ }
+ }
+ });
+ },
+ _createUploadButton: function(spec) {
+ var self = this, acceptFiles = spec.accept || this._options.validation.acceptFiles, allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions, button;
+ function allowMultiple() {
+ if (qq.supportedFeatures.ajaxUploading) {
+ if (self._options.workarounds.iosEmptyVideos && qq.ios() && !qq.ios6() && self._isAllowedExtension(allowedExtensions, ".mov")) {
+ return false;
+ }
+ if (spec.multiple === undefined) {
+ return self._options.multiple;
+ }
+ return spec.multiple;
+ }
+ return false;
+ }
+ button = new qq.UploadButton({
+ acceptFiles: acceptFiles,
+ element: spec.element,
+ focusClass: this._options.classes.buttonFocus,
+ folders: spec.folders,
+ hoverClass: this._options.classes.buttonHover,
+ ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,
+ multiple: allowMultiple(),
+ name: this._options.request.inputName,
+ onChange: function(input) {
+ self._onInputChange(input);
+ },
+ title: spec.title == null ? this._options.text.fileInputTitle : spec.title
+ });
+ this._disposeSupport.addDisposer(function() {
+ button.dispose();
+ });
+ self._buttons.push(button);
+ return button;
+ },
+ _createUploadHandler: function(additionalOptions, namespace) {
+ var self = this, lastOnProgress = {}, options = {
+ debug: this._options.debug,
+ maxConnections: this._options.maxConnections,
+ cors: this._options.cors,
+ paramsStore: this._paramsStore,
+ endpointStore: this._endpointStore,
+ chunking: this._options.chunking,
+ resume: this._options.resume,
+ blobs: this._options.blobs,
+ log: qq.bind(self.log, self),
+ preventRetryParam: this._options.retry.preventRetryResponseProperty,
+ onProgress: function(id, name, loaded, total) {
+ if (loaded < 0 || total < 0) {
+ return;
+ }
+ if (lastOnProgress[id]) {
+ if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ } else {
+ self._onProgress(id, name, loaded, total);
+ self._options.callbacks.onProgress(id, name, loaded, total);
+ }
+ lastOnProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onComplete: function(id, name, result, xhr) {
+ delete lastOnProgress[id];
+ var status = self.getUploads({
+ id: id
+ }).status, retVal;
+ if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {
+ return;
+ }
+ retVal = self._onComplete(id, name, result, xhr);
+ if (retVal instanceof qq.Promise) {
+ retVal.done(function() {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ });
+ } else {
+ self._options.callbacks.onComplete(id, name, result, xhr);
+ }
+ },
+ onCancel: function(id, name, cancelFinalizationEffort) {
+ var promise = new qq.Promise();
+ self._handleCheckedCallback({
+ name: "onCancel",
+ callback: qq.bind(self._options.callbacks.onCancel, self, id, name),
+ onFailure: promise.failure,
+ onSuccess: function() {
+ cancelFinalizationEffort.then(function() {
+ self._onCancel(id, name);
+ });
+ promise.success();
+ },
+ identifier: id
+ });
+ return promise;
+ },
+ onUploadPrep: qq.bind(this._onUploadPrep, this),
+ onUpload: function(id, name) {
+ self._onUpload(id, name);
+ self._options.callbacks.onUpload(id, name);
+ },
+ onUploadChunk: function(id, name, chunkData) {
+ self._onUploadChunk(id, chunkData);
+ self._options.callbacks.onUploadChunk(id, name, chunkData);
+ },
+ onUploadChunkSuccess: function(id, chunkData, result, xhr) {
+ self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);
+ },
+ onResume: function(id, name, chunkData) {
+ return self._options.callbacks.onResume(id, name, chunkData);
+ },
+ onAutoRetry: function(id, name, responseJSON, xhr) {
+ return self._onAutoRetry.apply(self, arguments);
+ },
+ onUuidChanged: function(id, newUuid) {
+ self.log("Server requested UUID change from '" + self.getUuid(id) + "' to '" + newUuid + "'");
+ self.setUuid(id, newUuid);
+ },
+ getName: qq.bind(self.getName, self),
+ getUuid: qq.bind(self.getUuid, self),
+ getSize: qq.bind(self.getSize, self),
+ setSize: qq.bind(self._setSize, self),
+ getDataByUuid: function(uuid) {
+ return self.getUploads({
+ uuid: uuid
+ });
+ },
+ isQueued: function(id) {
+ var status = self.getUploads({
+ id: id
+ }).status;
+ return status === qq.status.QUEUED || status === qq.status.SUBMITTED || status === qq.status.UPLOAD_RETRYING || status === qq.status.PAUSED;
+ },
+ getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,
+ getIdsInBatch: self._uploadData.getIdsInBatch
+ };
+ qq.each(this._options.request, function(prop, val) {
+ options[prop] = val;
+ });
+ options.customHeaders = this._customHeadersStore;
+ if (additionalOptions) {
+ qq.each(additionalOptions, function(key, val) {
+ options[key] = val;
+ });
+ }
+ return new qq.UploadHandlerController(options, namespace);
+ },
+ _fileOrBlobRejected: function(id) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.REJECTED);
+ },
+ _formatSize: function(bytes) {
+ if (bytes === 0) {
+ return bytes + this._options.text.sizeSymbols[0];
+ }
+ var i = -1;
+ do {
+ bytes = bytes / 1e3;
+ i++;
+ } while (bytes > 999);
+ return Math.max(bytes, .1).toFixed(1) + this._options.text.sizeSymbols[i];
+ },
+ _generateExtraButtonSpecs: function() {
+ var self = this;
+ this._extraButtonSpecs = {};
+ qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {
+ var multiple = extraButtonOptionEntry.multiple, validation = qq.extend({}, self._options.validation, true), extraButtonSpec = qq.extend({}, extraButtonOptionEntry);
+ if (multiple === undefined) {
+ multiple = self._options.multiple;
+ }
+ if (extraButtonSpec.validation) {
+ qq.extend(validation, extraButtonOptionEntry.validation, true);
+ }
+ qq.extend(extraButtonSpec, {
+ multiple: multiple,
+ validation: validation
+ }, true);
+ self._initExtraButton(extraButtonSpec);
+ });
+ },
+ _getButton: function(buttonId) {
+ var extraButtonsSpec = this._extraButtonSpecs[buttonId];
+ if (extraButtonsSpec) {
+ return extraButtonsSpec.element;
+ } else if (buttonId === this._defaultButtonId) {
+ return this._options.button;
+ }
+ },
+ _getButtonId: function(buttonOrFileInputOrFile) {
+ var inputs, fileInput, fileBlobOrInput = buttonOrFileInputOrFile;
+ if (fileBlobOrInput instanceof qq.BlobProxy) {
+ fileBlobOrInput = fileBlobOrInput.referenceBlob;
+ }
+ if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {
+ if (qq.isFile(fileBlobOrInput)) {
+ return fileBlobOrInput.qqButtonId;
+ } else if (fileBlobOrInput.tagName.toLowerCase() === "input" && fileBlobOrInput.type.toLowerCase() === "file") {
+ return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ inputs = fileBlobOrInput.getElementsByTagName("input");
+ qq.each(inputs, function(idx, input) {
+ if (input.getAttribute("type") === "file") {
+ fileInput = input;
+ return false;
+ }
+ });
+ if (fileInput) {
+ return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);
+ }
+ }
+ },
+ _getNotFinished: function() {
+ return this._uploadData.retrieve({
+ status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED, qq.status.SUBMITTING, qq.status.SUBMITTED, qq.status.PAUSED ]
+ }).length;
+ },
+ _getValidationBase: function(buttonId) {
+ var extraButtonSpec = this._extraButtonSpecs[buttonId];
+ return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;
+ },
+ _getValidationDescriptor: function(fileWrapper) {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return {
+ name: qq.getFilename(fileWrapper.file.referenceBlob),
+ size: fileWrapper.file.referenceBlob.size
+ };
+ }
+ return {
+ name: this.getUploads({
+ id: fileWrapper.id
+ }).name,
+ size: this.getUploads({
+ id: fileWrapper.id
+ }).size
+ };
+ },
+ _getValidationDescriptors: function(fileWrappers) {
+ var self = this, fileDescriptors = [];
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ fileDescriptors.push(self._getValidationDescriptor(fileWrapper));
+ });
+ return fileDescriptors;
+ },
+ _handleCameraAccess: function() {
+ if (this._options.camera.ios && qq.ios()) {
+ var acceptIosCamera = "image/*;capture=camera", button = this._options.camera.button, buttonId = button ? this._getButtonId(button) : this._defaultButtonId, optionRoot = this._options;
+ if (buttonId && buttonId !== this._defaultButtonId) {
+ optionRoot = this._extraButtonSpecs[buttonId];
+ }
+ optionRoot.multiple = false;
+ if (optionRoot.validation.acceptFiles === null) {
+ optionRoot.validation.acceptFiles = acceptIosCamera;
+ } else {
+ optionRoot.validation.acceptFiles += "," + acceptIosCamera;
+ }
+ qq.each(this._buttons, function(idx, button) {
+ if (button.getButtonId() === buttonId) {
+ button.setMultiple(optionRoot.multiple);
+ button.setAcceptFiles(optionRoot.acceptFiles);
+ return false;
+ }
+ });
+ }
+ },
+ _handleCheckedCallback: function(details) {
+ var self = this, callbackRetVal = details.callback();
+ if (qq.isGenericPromise(callbackRetVal)) {
+ this.log(details.name + " - waiting for " + details.name + " promise to be fulfilled for " + details.identifier);
+ return callbackRetVal.then(function(successParam) {
+ self.log(details.name + " promise success for " + details.identifier);
+ details.onSuccess(successParam);
+ }, function() {
+ if (details.onFailure) {
+ self.log(details.name + " promise failure for " + details.identifier);
+ details.onFailure();
+ } else {
+ self.log(details.name + " promise failure for " + details.identifier);
+ }
+ });
+ }
+ if (callbackRetVal !== false) {
+ details.onSuccess(callbackRetVal);
+ } else {
+ if (details.onFailure) {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Invoking failure callback.");
+ details.onFailure();
+ } else {
+ this.log(details.name + " - return value was 'false' for " + details.identifier + ". Will not proceed.");
+ }
+ }
+ return callbackRetVal;
+ },
+ _handleNewFile: function(file, batchId, newFileWrapperList) {
+ var self = this, uuid = qq.getUniqueId(), size = -1, name = qq.getFilename(file), actualFile = file.blob || file, handler = this._customNewFileHandler ? this._customNewFileHandler : qq.bind(self._handleNewFileGeneric, self);
+ if (!qq.isInput(actualFile) && actualFile.size >= 0) {
+ size = actualFile.size;
+ }
+ handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {
+ uploadData: self._uploadData,
+ paramsStore: self._paramsStore,
+ addFileToHandler: function(id, file) {
+ self._handler.add(id, file);
+ self._netUploadedOrQueued++;
+ self._trackButton(id);
+ }
+ });
+ },
+ _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {
+ var id = this._uploadData.addFile({
+ uuid: uuid,
+ name: name,
+ size: size,
+ batchId: batchId
+ });
+ this._handler.add(id, file);
+ this._trackButton(id);
+ this._netUploadedOrQueued++;
+ fileList.push({
+ id: id,
+ file: file
+ });
+ },
+ _handlePasteSuccess: function(blob, extSuppliedName) {
+ var extension = blob.type.split("/")[1], name = extSuppliedName;
+ if (name == null) {
+ name = this._options.paste.defaultName;
+ }
+ name += "." + extension;
+ this.addFiles({
+ name: name,
+ blob: blob
+ });
+ },
+ _initExtraButton: function(spec) {
+ var button = this._createUploadButton({
+ accept: spec.validation.acceptFiles,
+ allowedExtensions: spec.validation.allowedExtensions,
+ element: spec.element,
+ folders: spec.folders,
+ multiple: spec.multiple,
+ title: spec.fileInputTitle
+ });
+ this._extraButtonSpecs[button.getButtonId()] = spec;
+ },
+ _initFormSupportAndParams: function() {
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore = this._createStore(this._options.request.params, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this._options.request.endpoint = this._formSupport.newEndpoint;
+ }
+ } else {
+ this._paramsStore = this._createStore(this._options.request.params);
+ }
+ },
+ _isDeletePossible: function() {
+ if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {
+ return false;
+ }
+ if (this._options.cors.expected) {
+ if (qq.supportedFeatures.deleteFileCorsXhr) {
+ return true;
+ }
+ if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ },
+ _isAllowedExtension: function(allowed, fileName) {
+ var valid = false;
+ if (!allowed.length) {
+ return true;
+ }
+ qq.each(allowed, function(idx, allowedExt) {
+ if (qq.isString(allowedExt)) {
+ var extRegex = new RegExp("\\." + allowedExt + "$", "i");
+ if (fileName.match(extRegex) != null) {
+ valid = true;
+ return false;
+ }
+ }
+ });
+ return valid;
+ },
+ _itemError: function(code, maybeNameOrNames, item) {
+ var message = this._options.messages[code], allowedExtensions = [], names = [].concat(maybeNameOrNames), name = names[0], buttonId = this._getButtonId(item), validationBase = this._getValidationBase(buttonId), extensionsForMessage, placeholderMatch;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {
+ if (qq.isString(allowedExtension)) {
+ allowedExtensions.push(allowedExtension);
+ }
+ });
+ extensionsForMessage = allowedExtensions.join(", ").toLowerCase();
+ r("{file}", this._options.formatFileName(name));
+ r("{extensions}", extensionsForMessage);
+ r("{sizeLimit}", this._formatSize(validationBase.sizeLimit));
+ r("{minSizeLimit}", this._formatSize(validationBase.minSizeLimit));
+ placeholderMatch = message.match(/(\{\w+\})/g);
+ if (placeholderMatch !== null) {
+ qq.each(placeholderMatch, function(idx, placeholder) {
+ r(placeholder, names[idx]);
+ });
+ }
+ this._options.callbacks.onError(null, name, message, undefined);
+ return message;
+ },
+ _manualRetry: function(id, callback) {
+ if (this._onBeforeManualRetry(id)) {
+ this._netUploadedOrQueued++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ if (callback) {
+ callback(id);
+ } else {
+ this._handler.retry(id);
+ }
+ return true;
+ }
+ },
+ _maybeAllComplete: function(id, status) {
+ var self = this, notFinished = this._getNotFinished();
+ if (status === qq.status.UPLOAD_SUCCESSFUL) {
+ this._succeededSinceLastAllComplete.push(id);
+ } else if (status === qq.status.UPLOAD_FAILED) {
+ this._failedSinceLastAllComplete.push(id);
+ }
+ if (notFinished === 0 && (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {
+ setTimeout(function() {
+ self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);
+ }, 0);
+ }
+ },
+ _maybeHandleIos8SafariWorkaround: function() {
+ var self = this;
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ setTimeout(function() {
+ window.alert(self._options.messages.unsupportedBrowserIos8Safari);
+ }, 0);
+ throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);
+ }
+ },
+ _maybeParseAndSendUploadError: function(id, name, response, xhr) {
+ if (!response.success) {
+ if (xhr && xhr.status !== 200 && !response.error) {
+ this._options.callbacks.onError(id, name, "XHR returned response code " + xhr.status, xhr);
+ } else {
+ var errorReason = response.error ? response.error : this._options.text.defaultResponseError;
+ this._options.callbacks.onError(id, name, errorReason, xhr);
+ }
+ }
+ },
+ _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {
+ var self = this;
+ if (items.length > index) {
+ if (validItem || !this._options.validation.stopOnFirstInvalidFile) {
+ setTimeout(function() {
+ var validationDescriptor = self._getValidationDescriptor(items[index]), buttonId = self._getButtonId(items[index].file), button = self._getButton(buttonId);
+ self._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),
+ onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),
+ onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),
+ identifier: "Item '" + validationDescriptor.name + "', size: " + validationDescriptor.size
+ });
+ }, 0);
+ } else if (!validItem) {
+ for (;index < items.length; index++) {
+ self._fileOrBlobRejected(items[index].id);
+ }
+ }
+ }
+ },
+ _onAllComplete: function(successful, failed) {
+ this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);
+ this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ },
+ _onAutoRetry: function(id, name, responseJSON, xhr, callback) {
+ var self = this;
+ self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];
+ if (self._shouldAutoRetry(id, name, responseJSON)) {
+ var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1e3;
+ self._maybeParseAndSendUploadError.apply(self, arguments);
+ self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);
+ self._onBeforeAutoRetry(id, name);
+ self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);
+ self._retryTimeouts[id] = setTimeout(function() {
+ self.log("Starting retry for " + name + "...");
+ if (callback) {
+ callback(id);
+ } else {
+ self._handler.retry(id);
+ }
+ }, retryWaitPeriod);
+ return true;
+ }
+ },
+ _onBeforeAutoRetry: function(id, name) {
+ this.log("Waiting " + this._options.retry.autoAttemptDelay + " seconds before retrying " + name + "...");
+ },
+ _onBeforeManualRetry: function(id) {
+ var itemLimit = this._currentItemLimit, fileName;
+ if (this._preventRetries[id]) {
+ this.log("Retries are forbidden for id " + id, "warn");
+ return false;
+ } else if (this._handler.isValid(id)) {
+ fileName = this.getName(id);
+ if (this._options.callbacks.onManualRetry(id, fileName) === false) {
+ return false;
+ }
+ if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {
+ this._itemError("retryFailTooManyItems");
+ return false;
+ }
+ this.log("Retrying upload for '" + fileName + "' (id: " + id + ")...");
+ return true;
+ } else {
+ this.log("'" + id + "' is not a valid file ID", "error");
+ return false;
+ }
+ },
+ _onCancel: function(id, name) {
+ this._netUploadedOrQueued--;
+ clearTimeout(this._retryTimeouts[id]);
+ var storedItemIndex = qq.indexOf(this._storedIds, id);
+ if (!this._options.autoUpload && storedItemIndex >= 0) {
+ this._storedIds.splice(storedItemIndex, 1);
+ }
+ this._uploadData.setStatus(id, qq.status.CANCELED);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ if (!result.success) {
+ this._netUploadedOrQueued--;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);
+ if (result[this._options.retry.preventRetryResponseProperty] === true) {
+ this._preventRetries[id] = true;
+ }
+ } else {
+ if (result.thumbnailUrl) {
+ this._thumbnailUrls[id] = result.thumbnailUrl;
+ }
+ this._netUploaded++;
+ this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);
+ }
+ this._maybeParseAndSendUploadError(id, name, result, xhr);
+ return result.success ? true : false;
+ },
+ _onDelete: function(id) {
+ this._uploadData.setStatus(id, qq.status.DELETING);
+ },
+ _onDeleteComplete: function(id, xhrOrXdr, isError) {
+ var name = this.getName(id);
+ if (isError) {
+ this._uploadData.setStatus(id, qq.status.DELETE_FAILED);
+ this.log("Delete request for '" + name + "' has failed.", "error");
+ if (xhrOrXdr.withCredentials === undefined) {
+ this._options.callbacks.onError(id, name, "Delete request failed", xhrOrXdr);
+ } else {
+ this._options.callbacks.onError(id, name, "Delete request failed with response code " + xhrOrXdr.status, xhrOrXdr);
+ }
+ } else {
+ this._netUploadedOrQueued--;
+ this._netUploaded--;
+ this._handler.expunge(id);
+ this._uploadData.setStatus(id, qq.status.DELETED);
+ this.log("Delete request for '" + name + "' has succeeded.");
+ }
+ },
+ _onInputChange: function(input) {
+ var fileIndex;
+ if (qq.supportedFeatures.ajaxUploading) {
+ for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {
+ this._annotateWithButtonId(input.files[fileIndex], input);
+ }
+ this.addFiles(input.files);
+ } else if (input.value.length > 0) {
+ this.addFiles(input);
+ }
+ qq.each(this._buttons, function(idx, button) {
+ button.reset();
+ });
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);
+ },
+ _onSubmit: function(id, name) {},
+ _onSubmitCallbackSuccess: function(id, name) {
+ this._onSubmit.apply(this, arguments);
+ this._uploadData.setStatus(id, qq.status.SUBMITTED);
+ this._onSubmitted.apply(this, arguments);
+ if (this._options.autoUpload) {
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ this._uploadFile(id);
+ } else {
+ this._storeForLater(id);
+ this._options.callbacks.onSubmitted.apply(this, arguments);
+ }
+ },
+ _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {
+ var uuid = this.getUuid(id), adjustedOnSuccessCallback;
+ if (onSuccessCallback) {
+ adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);
+ }
+ if (this._isDeletePossible()) {
+ this._handleCheckedCallback({
+ name: "onSubmitDelete",
+ callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),
+ onSuccess: adjustedOnSuccessCallback || qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),
+ identifier: id
+ });
+ return true;
+ } else {
+ this.log("Delete request ignored for ID " + id + ", delete feature is disabled or request not possible " + "due to CORS on a user agent that does not support pre-flighting.", "warn");
+ return false;
+ }
+ },
+ _onSubmitted: function(id) {},
+ _onTotalProgress: function(loaded, total) {
+ this._options.callbacks.onTotalProgress(loaded, total);
+ },
+ _onUploadPrep: function(id) {},
+ _onUpload: function(id, name) {
+ this._uploadData.setStatus(id, qq.status.UPLOADING);
+ },
+ _onUploadChunk: function(id, chunkData) {},
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.PAUSED) {
+ clearTimeout(this._retryTimeouts[id]);
+ }
+ },
+ _onValidateBatchCallbackFailure: function(fileWrappers) {
+ var self = this;
+ qq.each(fileWrappers, function(idx, fileWrapper) {
+ self._fileOrBlobRejected(fileWrapper.id);
+ });
+ },
+ _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {
+ var errorMessage, itemLimit = this._currentItemLimit, proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;
+ if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {
+ if (items.length > 0) {
+ this._handleCheckedCallback({
+ name: "onValidate",
+ callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),
+ onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),
+ onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),
+ identifier: "Item '" + items[0].file.name + "', size: " + items[0].file.size
+ });
+ } else {
+ this._itemError("noFilesError");
+ }
+ } else {
+ this._onValidateBatchCallbackFailure(items);
+ errorMessage = this._options.messages.tooManyItemsError.replace(/\{netItems\}/g, proposedNetFilesUploadedOrQueued).replace(/\{itemLimit\}/g, itemLimit);
+ this._batchError(errorMessage);
+ }
+ },
+ _onValidateCallbackFailure: function(items, index, params, endpoint) {
+ var nextIndex = index + 1;
+ this._fileOrBlobRejected(items[index].id, items[index].file.name);
+ this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ },
+ _onValidateCallbackSuccess: function(items, index, params, endpoint) {
+ var self = this, nextIndex = index + 1, validationDescriptor = this._getValidationDescriptor(items[index]);
+ this._validateFileOrBlobData(items[index], validationDescriptor).then(function() {
+ self._upload(items[index].id, params, endpoint);
+ self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);
+ }, function() {
+ self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);
+ });
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ if (items.length === 0) {
+ this._itemError("noFilesError");
+ return;
+ }
+ var validationDescriptors = this._getValidationDescriptors(items), buttonId = this._getButtonId(items[0].file), button = this._getButton(buttonId);
+ this._handleCheckedCallback({
+ name: "onValidateBatch",
+ callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),
+ onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),
+ onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),
+ identifier: "batch validation"
+ });
+ },
+ _preventLeaveInProgress: function() {
+ var self = this;
+ this._disposeSupport.attach(window, "beforeunload", function(e) {
+ if (self.getInProgress()) {
+ e = e || window.event;
+ e.returnValue = self._options.messages.onLeave;
+ return self._options.messages.onLeave;
+ }
+ });
+ },
+ _refreshSessionData: function() {
+ var self = this, options = this._options.session;
+ if (qq.Session && this._options.session.endpoint != null) {
+ if (!this._session) {
+ qq.extend(options, {
+ cors: this._options.cors
+ });
+ options.log = qq.bind(this.log, this);
+ options.addFileRecord = qq.bind(this._addCannedFile, this);
+ this._session = new qq.Session(options);
+ }
+ setTimeout(function() {
+ self._session.refresh().then(function(response, xhrOrXdr) {
+ self._sessionRequestComplete();
+ self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);
+ }, function(response, xhrOrXdr) {
+ self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);
+ });
+ }, 0);
+ }
+ },
+ _sessionRequestComplete: function() {},
+ _setSize: function(id, newSize) {
+ this._uploadData.updateSize(id, newSize);
+ this._totalProgress && this._totalProgress.onNewSize(id);
+ },
+ _shouldAutoRetry: function(id, name, responseJSON) {
+ var uploadData = this._uploadData.retrieve({
+ id: id
+ });
+ if (!this._preventRetries[id] && this._options.retry.enableAuto && uploadData.status !== qq.status.PAUSED) {
+ if (this._autoRetries[id] === undefined) {
+ this._autoRetries[id] = 0;
+ }
+ if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {
+ this._autoRetries[id] += 1;
+ return true;
+ }
+ }
+ return false;
+ },
+ _storeForLater: function(id) {
+ this._storedIds.push(id);
+ },
+ _trackButton: function(id) {
+ var buttonId;
+ if (qq.supportedFeatures.ajaxUploading) {
+ buttonId = this._handler.getFile(id).qqButtonId;
+ } else {
+ buttonId = this._getButtonId(this._handler.getInput(id));
+ }
+ if (buttonId) {
+ this._buttonIdsForFileIds[id] = buttonId;
+ }
+ },
+ _updateFormSupportAndParams: function(formElementOrId) {
+ this._options.form.element = formElementOrId;
+ this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this));
+ if (this._formSupport && this._formSupport.attachedToForm) {
+ this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);
+ this._options.autoUpload = this._formSupport.newAutoUpload;
+ if (this._formSupport.newEndpoint) {
+ this.setEndpoint(this._formSupport.newEndpoint);
+ }
+ }
+ },
+ _upload: function(id, params, endpoint) {
+ var name = this.getName(id);
+ if (params) {
+ this.setParams(params, id);
+ }
+ if (endpoint) {
+ this.setEndpoint(endpoint, id);
+ }
+ this._handleCheckedCallback({
+ name: "onSubmit",
+ callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),
+ onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),
+ onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),
+ identifier: id
+ });
+ },
+ _uploadFile: function(id) {
+ if (!this._handler.upload(id)) {
+ this._uploadData.setStatus(id, qq.status.QUEUED);
+ }
+ },
+ _uploadStoredFiles: function() {
+ var idToUpload, stillSubmitting, self = this;
+ while (this._storedIds.length) {
+ idToUpload = this._storedIds.shift();
+ this._uploadFile(idToUpload);
+ }
+ stillSubmitting = this.getUploads({
+ status: qq.status.SUBMITTING
+ }).length;
+ if (stillSubmitting) {
+ qq.log("Still waiting for " + stillSubmitting + " files to clear submit queue. Will re-parse stored IDs array shortly.");
+ setTimeout(function() {
+ self._uploadStoredFiles();
+ }, 1e3);
+ }
+ },
+ _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {
+ var self = this, file = function() {
+ if (fileWrapper.file instanceof qq.BlobProxy) {
+ return fileWrapper.file.referenceBlob;
+ }
+ return fileWrapper.file;
+ }(), name = validationDescriptor.name, size = validationDescriptor.size, buttonId = this._getButtonId(fileWrapper.file), validationBase = this._getValidationBase(buttonId), validityChecker = new qq.Promise();
+ validityChecker.then(function() {}, function() {
+ self._fileOrBlobRejected(fileWrapper.id, name);
+ });
+ if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {
+ this._itemError("typeError", name, file);
+ return validityChecker.failure();
+ }
+ if (!this._options.validation.allowEmpty && size === 0) {
+ this._itemError("emptyError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {
+ this._itemError("sizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (size > 0 && size < validationBase.minSizeLimit) {
+ this._itemError("minSizeError", name, file);
+ return validityChecker.failure();
+ }
+ if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {
+ new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(validityChecker.success, function(errorCode) {
+ self._itemError(errorCode + "ImageError", name, file);
+ validityChecker.failure();
+ });
+ } else {
+ validityChecker.success();
+ }
+ return validityChecker;
+ },
+ _wrapCallbacks: function() {
+ var self, safeCallback, prop;
+ self = this;
+ safeCallback = function(name, callback, args) {
+ var errorMsg;
+ try {
+ return callback.apply(self, args);
+ } catch (exception) {
+ errorMsg = exception.message || exception.toString();
+ self.log("Caught exception in '" + name + "' callback - " + errorMsg, "error");
+ }
+ };
+ for (prop in this._options.callbacks) {
+ (function() {
+ var callbackName, callbackFunc;
+ callbackName = prop;
+ callbackFunc = self._options.callbacks[callbackName];
+ self._options.callbacks[callbackName] = function() {
+ return safeCallback(callbackName, callbackFunc, arguments);
+ };
+ })();
+ }
+ }
+ };
+ })();
+ (function() {
+ "use strict";
+ qq.FineUploaderBasic = function(o) {
+ var self = this;
+ this._options = {
+ debug: false,
+ button: null,
+ multiple: true,
+ maxConnections: 3,
+ disableCancelForFormUploads: false,
+ autoUpload: true,
+ request: {
+ customHeaders: {},
+ endpoint: "/server/upload",
+ filenameParam: "qqfilename",
+ forceMultipart: true,
+ inputName: "qqfile",
+ method: "POST",
+ params: {},
+ paramsInBody: true,
+ totalFileSizeName: "qqtotalfilesize",
+ uuidName: "qquuid"
+ },
+ validation: {
+ allowedExtensions: [],
+ sizeLimit: 0,
+ minSizeLimit: 0,
+ itemLimit: 0,
+ stopOnFirstInvalidFile: true,
+ acceptFiles: null,
+ image: {
+ maxHeight: 0,
+ maxWidth: 0,
+ minHeight: 0,
+ minWidth: 0
+ },
+ allowEmpty: false
+ },
+ callbacks: {
+ onSubmit: function(id, name) {},
+ onSubmitted: function(id, name) {},
+ onComplete: function(id, name, responseJSON, maybeXhr) {},
+ onAllComplete: function(successful, failed) {},
+ onCancel: function(id, name) {},
+ onUpload: function(id, name) {},
+ onUploadChunk: function(id, name, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onProgress: function(id, name, loaded, total) {},
+ onTotalProgress: function(loaded, total) {},
+ onError: function(id, name, reason, maybeXhrOrXdr) {},
+ onAutoRetry: function(id, name, attemptNumber) {},
+ onManualRetry: function(id, name) {},
+ onValidateBatch: function(fileOrBlobData) {},
+ onValidate: function(fileOrBlobData) {},
+ onSubmitDelete: function(id) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {},
+ onPasteReceived: function(blob) {},
+ onStatusChange: function(id, oldStatus, newStatus) {},
+ onSessionRequestComplete: function(response, success, xhrOrXdr) {}
+ },
+ messages: {
+ typeError: "{file} has an invalid extension. Valid extension(s): {extensions}.",
+ sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
+ minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
+ emptyError: "{file} is empty, please select files again without it.",
+ noFilesError: "No files to upload.",
+ tooManyItemsError: "Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.",
+ maxHeightImageError: "Image is too tall.",
+ maxWidthImageError: "Image is too wide.",
+ minHeightImageError: "Image is not tall enough.",
+ minWidthImageError: "Image is not wide enough.",
+ retryFailTooManyItems: "Retry failed - you have reached your file limit.",
+ onLeave: "The files are being uploaded, if you leave now the upload will be canceled.",
+ unsupportedBrowserIos8Safari: "Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues."
+ },
+ retry: {
+ enableAuto: false,
+ maxAutoAttempts: 3,
+ autoAttemptDelay: 5,
+ preventRetryResponseProperty: "preventRetry"
+ },
+ classes: {
+ buttonHover: "qq-upload-button-hover",
+ buttonFocus: "qq-upload-button-focus"
+ },
+ chunking: {
+ enabled: false,
+ concurrent: {
+ enabled: false
+ },
+ mandatory: false,
+ paramNames: {
+ partIndex: "qqpartindex",
+ partByteOffset: "qqpartbyteoffset",
+ chunkSize: "qqchunksize",
+ totalFileSize: "qqtotalfilesize",
+ totalParts: "qqtotalparts"
+ },
+ partSize: 2e6,
+ success: {
+ endpoint: null
+ }
+ },
+ resume: {
+ enabled: false,
+ recordsExpireIn: 7,
+ paramNames: {
+ resuming: "qqresume"
+ }
+ },
+ formatFileName: function(fileOrBlobName) {
+ return fileOrBlobName;
+ },
+ text: {
+ defaultResponseError: "Upload failure reason unknown",
+ fileInputTitle: "file input",
+ sizeSymbols: [ "kB", "MB", "GB", "TB", "PB", "EB" ]
+ },
+ deleteFile: {
+ enabled: false,
+ method: "DELETE",
+ endpoint: "/server/upload",
+ customHeaders: {},
+ params: {}
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false,
+ allowXdr: false
+ },
+ blobs: {
+ defaultName: "misc_data"
+ },
+ paste: {
+ targetElement: null,
+ defaultName: "pasted_image"
+ },
+ camera: {
+ ios: false,
+ button: null
+ },
+ extraButtons: [],
+ session: {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ refreshOnReset: true
+ },
+ form: {
+ element: "qq-form",
+ autoUpload: false,
+ interceptSubmit: true
+ },
+ scaling: {
+ customResizer: null,
+ sendOriginal: true,
+ orient: true,
+ defaultType: null,
+ defaultQuality: 80,
+ failureText: "Failed to scale",
+ includeExif: false,
+ sizes: []
+ },
+ workarounds: {
+ iosEmptyVideos: true,
+ ios8SafariUploads: true,
+ ios8BrowserCrash: false
+ }
+ };
+ qq.extend(this._options, o, true);
+ this._buttons = [];
+ this._extraButtonSpecs = {};
+ this._buttonIdsForFileIds = [];
+ this._wrapCallbacks();
+ this._disposeSupport = new qq.DisposeSupport();
+ this._storedIds = [];
+ this._autoRetries = [];
+ this._retryTimeouts = [];
+ this._preventRetries = [];
+ this._thumbnailUrls = [];
+ this._netUploadedOrQueued = 0;
+ this._netUploaded = 0;
+ this._uploadData = this._createUploadDataTracker();
+ this._initFormSupportAndParams();
+ this._customHeadersStore = this._createStore(this._options.request.customHeaders);
+ this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);
+ this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);
+ this._endpointStore = this._createStore(this._options.request.endpoint);
+ this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);
+ this._handler = this._createUploadHandler();
+ this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();
+ if (this._options.button) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._options.button,
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._generateExtraButtonSpecs();
+ this._handleCameraAccess();
+ if (this._options.paste.targetElement) {
+ if (qq.PasteSupport) {
+ this._pasteHandler = this._createPasteHandler();
+ } else {
+ this.log("Paste support module not found", "error");
+ }
+ }
+ this._preventLeaveInProgress();
+ this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));
+ this._refreshSessionData();
+ this._succeededSinceLastAllComplete = [];
+ this._failedSinceLastAllComplete = [];
+ this._scaler = qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this)) || {};
+ if (this._scaler.enabled) {
+ this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);
+ }
+ if (qq.TotalProgress && qq.supportedFeatures.progressBar) {
+ this._totalProgress = new qq.TotalProgress(qq.bind(this._onTotalProgress, this), function(id) {
+ var entry = self._uploadData.retrieve({
+ id: id
+ });
+ return entry && entry.size || 0;
+ });
+ }
+ this._currentItemLimit = this._options.validation.itemLimit;
+ };
+ qq.FineUploaderBasic.prototype = qq.basePublicApi;
+ qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);
+ })();
+ qq.AjaxRequester = function(o) {
+ "use strict";
+ var log, shouldParamsBeInQueryString, queue = [], requestData = {}, options = {
+ acceptHeader: null,
+ validMethods: [ "PATCH", "POST", "PUT" ],
+ method: "POST",
+ contentType: "application/x-www-form-urlencoded",
+ maxConnections: 3,
+ customHeaders: {},
+ endpointStore: {},
+ paramsStore: {},
+ mandatedParams: {},
+ allowXRequestedWithAndCacheControl: true,
+ successfulResponseCodes: {
+ DELETE: [ 200, 202, 204 ],
+ PATCH: [ 200, 201, 202, 203, 204 ],
+ POST: [ 200, 201, 202, 203, 204 ],
+ PUT: [ 200, 201, 202, 203, 204 ],
+ GET: [ 200 ]
+ },
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onSend: function(id) {},
+ onComplete: function(id, xhrOrXdr, isError) {},
+ onProgress: null
+ };
+ qq.extend(options, o);
+ log = options.log;
+ if (qq.indexOf(options.validMethods, options.method) < 0) {
+ throw new Error("'" + options.method + "' is not a supported method for this type of request!");
+ }
+ function isSimpleMethod() {
+ return qq.indexOf([ "GET", "POST", "HEAD" ], options.method) >= 0;
+ }
+ function containsNonSimpleHeaders(headers) {
+ var containsNonSimple = false;
+ qq.each(containsNonSimple, function(idx, header) {
+ if (qq.indexOf([ "Accept", "Accept-Language", "Content-Language", "Content-Type" ], header) < 0) {
+ containsNonSimple = true;
+ return false;
+ }
+ });
+ return containsNonSimple;
+ }
+ function isXdr(xhr) {
+ return options.cors.expected && xhr.withCredentials === undefined;
+ }
+ function getCorsAjaxTransport() {
+ var xhrOrXdr;
+ if (window.XMLHttpRequest || window.ActiveXObject) {
+ xhrOrXdr = qq.createXhrInstance();
+ if (xhrOrXdr.withCredentials === undefined) {
+ xhrOrXdr = new XDomainRequest();
+ xhrOrXdr.onload = function() {};
+ xhrOrXdr.onerror = function() {};
+ xhrOrXdr.ontimeout = function() {};
+ xhrOrXdr.onprogress = function() {};
+ }
+ }
+ return xhrOrXdr;
+ }
+ function getXhrOrXdr(id, suppliedXhr) {
+ var xhrOrXdr = requestData[id].xhr;
+ if (!xhrOrXdr) {
+ if (suppliedXhr) {
+ xhrOrXdr = suppliedXhr;
+ } else {
+ if (options.cors.expected) {
+ xhrOrXdr = getCorsAjaxTransport();
+ } else {
+ xhrOrXdr = qq.createXhrInstance();
+ }
+ }
+ requestData[id].xhr = xhrOrXdr;
+ }
+ return xhrOrXdr;
+ }
+ function dequeue(id) {
+ var i = qq.indexOf(queue, id), max = options.maxConnections, nextId;
+ delete requestData[id];
+ queue.splice(i, 1);
+ if (queue.length >= max && i < max) {
+ nextId = queue[max - 1];
+ sendRequest(nextId);
+ }
+ }
+ function onComplete(id, xdrError) {
+ var xhr = getXhrOrXdr(id), method = options.method, isError = xdrError === true;
+ dequeue(id);
+ if (isError) {
+ log(method + " request for " + id + " has failed", "error");
+ } else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {
+ isError = true;
+ log(method + " request for " + id + " has failed - response code " + xhr.status, "error");
+ }
+ options.onComplete(id, xhr, isError);
+ }
+ function getParams(id) {
+ var onDemandParams = requestData[id].additionalParams, mandatedParams = options.mandatedParams, params;
+ if (options.paramsStore.get) {
+ params = options.paramsStore.get(id);
+ }
+ if (onDemandParams) {
+ qq.each(onDemandParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ if (mandatedParams) {
+ qq.each(mandatedParams, function(name, val) {
+ params = params || {};
+ params[name] = val;
+ });
+ }
+ return params;
+ }
+ function sendRequest(id, optXhr) {
+ var xhr = getXhrOrXdr(id, optXhr), method = options.method, params = getParams(id), payload = requestData[id].payload, url;
+ options.onSend(id);
+ url = createUrl(id, params, requestData[id].additionalQueryParams);
+ if (isXdr(xhr)) {
+ xhr.onload = getXdrLoadHandler(id);
+ xhr.onerror = getXdrErrorHandler(id);
+ } else {
+ xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);
+ }
+ registerForUploadProgress(id);
+ xhr.open(method, url, true);
+ if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {
+ xhr.withCredentials = true;
+ }
+ setHeaders(id);
+ log("Sending " + method + " request for " + id);
+ if (payload) {
+ xhr.send(payload);
+ } else if (shouldParamsBeInQueryString || !params) {
+ xhr.send();
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/x-www-form-urlencoded") >= 0) {
+ xhr.send(qq.obj2url(params, ""));
+ } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/json") >= 0) {
+ xhr.send(JSON.stringify(params));
+ } else {
+ xhr.send(params);
+ }
+ return xhr;
+ }
+ function createUrl(id, params, additionalQueryParams) {
+ var endpoint = options.endpointStore.get(id), addToPath = requestData[id].addToPath;
+ if (addToPath != undefined) {
+ endpoint += "/" + addToPath;
+ }
+ if (shouldParamsBeInQueryString && params) {
+ endpoint = qq.obj2url(params, endpoint);
+ }
+ if (additionalQueryParams) {
+ endpoint = qq.obj2url(additionalQueryParams, endpoint);
+ }
+ return endpoint;
+ }
+ function getXhrReadyStateChangeHandler(id) {
+ return function() {
+ if (getXhrOrXdr(id).readyState === 4) {
+ onComplete(id);
+ }
+ };
+ }
+ function registerForUploadProgress(id) {
+ var onProgress = options.onProgress;
+ if (onProgress) {
+ getXhrOrXdr(id).upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ onProgress(id, e.loaded, e.total);
+ }
+ };
+ }
+ }
+ function getXdrLoadHandler(id) {
+ return function() {
+ onComplete(id);
+ };
+ }
+ function getXdrErrorHandler(id) {
+ return function() {
+ onComplete(id, true);
+ };
+ }
+ function setHeaders(id) {
+ var xhr = getXhrOrXdr(id), customHeaders = options.customHeaders, onDemandHeaders = requestData[id].additionalHeaders || {}, method = options.method, allHeaders = {};
+ if (!isXdr(xhr)) {
+ options.acceptHeader && xhr.setRequestHeader("Accept", options.acceptHeader);
+ if (options.allowXRequestedWithAndCacheControl) {
+ if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ xhr.setRequestHeader("Cache-Control", "no-cache");
+ }
+ }
+ if (options.contentType && (method === "POST" || method === "PUT")) {
+ xhr.setRequestHeader("Content-Type", options.contentType);
+ }
+ qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);
+ qq.extend(allHeaders, onDemandHeaders);
+ qq.each(allHeaders, function(name, val) {
+ xhr.setRequestHeader(name, val);
+ });
+ }
+ }
+ function isResponseSuccessful(responseCode) {
+ return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;
+ }
+ function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {
+ requestData[id] = {
+ addToPath: addToPath,
+ additionalParams: additionalParams,
+ additionalQueryParams: additionalQueryParams,
+ additionalHeaders: additionalHeaders,
+ payload: payload
+ };
+ var len = queue.push(id);
+ if (len <= options.maxConnections) {
+ return sendRequest(id, optXhr);
+ }
+ }
+ shouldParamsBeInQueryString = options.method === "GET" || options.method === "DELETE";
+ qq.extend(this, {
+ initTransport: function(id) {
+ var path, params, headers, payload, cacheBuster, additionalQueryParams;
+ return {
+ withPath: function(appendToPath) {
+ path = appendToPath;
+ return this;
+ },
+ withParams: function(additionalParams) {
+ params = additionalParams;
+ return this;
+ },
+ withQueryParams: function(_additionalQueryParams_) {
+ additionalQueryParams = _additionalQueryParams_;
+ return this;
+ },
+ withHeaders: function(additionalHeaders) {
+ headers = additionalHeaders;
+ return this;
+ },
+ withPayload: function(thePayload) {
+ payload = thePayload;
+ return this;
+ },
+ withCacheBuster: function() {
+ cacheBuster = true;
+ return this;
+ },
+ send: function(optXhr) {
+ if (cacheBuster && qq.indexOf([ "GET", "DELETE" ], options.method) >= 0) {
+ params.qqtimestamp = new Date().getTime();
+ }
+ return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);
+ }
+ };
+ },
+ canceled: function(id) {
+ dequeue(id);
+ }
+ });
+ };
+ qq.UploadHandler = function(spec) {
+ "use strict";
+ var proxy = spec.proxy, fileState = {}, onCancel = proxy.onCancel, getName = proxy.getName;
+ qq.extend(this, {
+ add: function(id, fileItem) {
+ fileState[id] = fileItem;
+ fileState[id].temp = {};
+ },
+ cancel: function(id) {
+ var self = this, cancelFinalizationEffort = new qq.Promise(), onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);
+ onCancelRetVal.then(function() {
+ if (self.isValid(id)) {
+ fileState[id].canceled = true;
+ self.expunge(id);
+ }
+ cancelFinalizationEffort.success();
+ });
+ },
+ expunge: function(id) {
+ delete fileState[id];
+ },
+ getThirdPartyFileId: function(id) {
+ return fileState[id].key;
+ },
+ isValid: function(id) {
+ return fileState[id] !== undefined;
+ },
+ reset: function() {
+ fileState = {};
+ },
+ _getFileState: function(id) {
+ return fileState[id];
+ },
+ _setThirdPartyFileId: function(id, thirdPartyFileId) {
+ fileState[id].key = thirdPartyFileId;
+ },
+ _wasCanceled: function(id) {
+ return !!fileState[id].canceled;
+ }
+ });
+ };
+ qq.UploadHandlerController = function(o, namespace) {
+ "use strict";
+ var controller = this, chunkingPossible = false, concurrentChunkingPossible = false, chunking, preventRetryResponse, log, handler, options = {
+ paramsStore: {},
+ maxConnections: 3,
+ chunking: {
+ enabled: false,
+ multiple: {
+ enabled: false
+ }
+ },
+ log: function(str, level) {},
+ onProgress: function(id, fileName, loaded, total) {},
+ onComplete: function(id, fileName, response, xhr) {},
+ onCancel: function(id, fileName) {},
+ onUploadPrep: function(id) {},
+ onUpload: function(id, fileName) {},
+ onUploadChunk: function(id, fileName, chunkData) {},
+ onUploadChunkSuccess: function(id, chunkData, response, xhr) {},
+ onAutoRetry: function(id, fileName, response, xhr) {},
+ onResume: function(id, fileName, chunkData) {},
+ onUuidChanged: function(id, newUuid) {},
+ getName: function(id) {},
+ setSize: function(id, newSize) {},
+ isQueued: function(id) {},
+ getIdsInProxyGroup: function(id) {},
+ getIdsInBatch: function(id) {}
+ }, chunked = {
+ done: function(id, chunkIdx, response, xhr) {
+ var chunkData = handler._getChunkData(id, chunkIdx);
+ handler._getFileState(id).attemptingResume = false;
+ delete handler._getFileState(id).temp.chunkProgress[chunkIdx];
+ handler._getFileState(id).loaded += chunkData.size;
+ options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);
+ },
+ finalize: function(id) {
+ var size = options.getSize(id), name = options.getName(id);
+ log("All chunks have been uploaded for " + id + " - finalizing....");
+ handler.finalizeChunks(id).then(function(response, xhr) {
+ log("Finalize successful for " + id);
+ var normaizedResponse = upload.normalizeResponse(response, true);
+ options.onProgress(id, name, size, size);
+ handler._maybeDeletePersistedChunkData(id);
+ upload.cleanup(id, normaizedResponse, xhr);
+ }, function(response, xhr) {
+ var normaizedResponse = upload.normalizeResponse(response, false);
+ log("Problem finalizing chunks for file ID " + id + " - " + normaizedResponse.error, "error");
+ if (normaizedResponse.reset) {
+ chunked.reset(id);
+ }
+ if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {
+ upload.cleanup(id, normaizedResponse, xhr);
+ }
+ });
+ },
+ handleFailure: function(chunkIdx, id, response, xhr) {
+ var name = options.getName(id);
+ log("Chunked upload request failed for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var responseToReport = upload.normalizeResponse(response, false), inProgressIdx;
+ if (responseToReport.reset) {
+ chunked.reset(id);
+ } else {
+ inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);
+ if (inProgressIdx >= 0) {
+ handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);
+ handler._getFileState(id).chunking.remaining.unshift(chunkIdx);
+ }
+ }
+ if (!handler._getFileState(id).temp.ignoreFailure) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = true;
+ log(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));
+ qq.each(handler._getXhrs(id), function(ckid, ckXhr) {
+ log(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ", id, ckid, ckXhr.readyState));
+ ckXhr.abort();
+ ckXhr._cancelled = true;
+ });
+ handler.moveInProgressToRemaining(id);
+ connectionManager.free(id, true);
+ }
+ if (!options.onAutoRetry(id, name, responseToReport, xhr)) {
+ upload.cleanup(id, responseToReport, xhr);
+ }
+ }
+ },
+ hasMoreParts: function(id) {
+ return !!handler._getFileState(id).chunking.remaining.length;
+ },
+ nextPart: function(id) {
+ var nextIdx = handler._getFileState(id).chunking.remaining.shift();
+ if (nextIdx >= handler._getTotalChunks(id)) {
+ nextIdx = null;
+ }
+ return nextIdx;
+ },
+ reset: function(id) {
+ log("Server or callback has ordered chunking effort to be restarted on next attempt for item ID " + id, "error");
+ handler._maybeDeletePersistedChunkData(id);
+ handler.reevaluateChunking(id);
+ handler._getFileState(id).loaded = 0;
+ },
+ sendNext: function(id) {
+ var size = options.getSize(id), name = options.getName(id), chunkIdx = chunked.nextPart(id), chunkData = handler._getChunkData(id, chunkIdx), resuming = handler._getFileState(id).attemptingResume, inProgressChunks = handler._getFileState(id).chunking.inProgress || [];
+ if (handler._getFileState(id).loaded == null) {
+ handler._getFileState(id).loaded = 0;
+ }
+ if (resuming && options.onResume(id, name, chunkData) === false) {
+ chunked.reset(id);
+ chunkIdx = chunked.nextPart(id);
+ chunkData = handler._getChunkData(id, chunkIdx);
+ resuming = false;
+ }
+ if (chunkIdx == null && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else {
+ log(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.", id, chunkIdx, chunkData.start + 1, chunkData.end, size));
+ options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));
+ inProgressChunks.push(chunkIdx);
+ handler._getFileState(id).chunking.inProgress = inProgressChunks;
+ if (concurrentChunkingPossible) {
+ connectionManager.open(id, chunkIdx);
+ }
+ if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {
+ chunked.sendNext(id);
+ }
+ if (chunkData.blob.size === 0) {
+ log(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.", chunkIdx, id), "error");
+ chunked.handleFailure(chunkIdx, id, "File is no longer available", null);
+ } else {
+ handler.uploadChunk(id, chunkIdx, resuming).then(function success(response, xhr) {
+ log("Chunked upload request succeeded for " + id + ", chunk " + chunkIdx);
+ handler.clearCachedChunk(id, chunkIdx);
+ var inProgressChunks = handler._getFileState(id).chunking.inProgress || [], responseToReport = upload.normalizeResponse(response, true), inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);
+ log(qq.format("Chunk {} for file {} uploaded successfully.", chunkIdx, id));
+ chunked.done(id, chunkIdx, responseToReport, xhr);
+ if (inProgressChunkIdx >= 0) {
+ inProgressChunks.splice(inProgressChunkIdx, 1);
+ }
+ handler._maybePersistChunkedState(id);
+ if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {
+ chunked.finalize(id);
+ } else if (chunked.hasMoreParts(id)) {
+ chunked.sendNext(id);
+ } else {
+ log(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}", id, JSON.stringify(inProgressChunks)));
+ }
+ }, function failure(response, xhr) {
+ chunked.handleFailure(chunkIdx, id, response, xhr);
+ }).done(function() {
+ handler.clearXhr(id, chunkIdx);
+ });
+ }
+ }
+ }
+ }, connectionManager = {
+ _open: [],
+ _openChunks: {},
+ _waiting: [],
+ available: function() {
+ var max = options.maxConnections, openChunkEntriesCount = 0, openChunksCount = 0;
+ qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {
+ openChunkEntriesCount++;
+ openChunksCount += openChunkIndexes.length;
+ });
+ return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);
+ },
+ free: function(id, dontAllowNext) {
+ var allowNext = !dontAllowNext, waitingIndex = qq.indexOf(connectionManager._waiting, id), connectionsIndex = qq.indexOf(connectionManager._open, id), nextId;
+ delete connectionManager._openChunks[id];
+ if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {
+ log("Generated blob upload has ended for " + id + ", disposing generated blob.");
+ delete handler._getFileState(id).file;
+ }
+ if (waitingIndex >= 0) {
+ connectionManager._waiting.splice(waitingIndex, 1);
+ } else if (allowNext && connectionsIndex >= 0) {
+ connectionManager._open.splice(connectionsIndex, 1);
+ nextId = connectionManager._waiting.shift();
+ if (nextId >= 0) {
+ connectionManager._open.push(nextId);
+ upload.start(nextId);
+ }
+ }
+ },
+ getWaitingOrConnected: function() {
+ var waitingOrConnected = [];
+ qq.each(connectionManager._openChunks, function(fileId, chunks) {
+ if (chunks && chunks.length) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ qq.each(connectionManager._open, function(idx, fileId) {
+ if (!connectionManager._openChunks[fileId]) {
+ waitingOrConnected.push(parseInt(fileId));
+ }
+ });
+ waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);
+ return waitingOrConnected;
+ },
+ isUsingConnection: function(id) {
+ return qq.indexOf(connectionManager._open, id) >= 0;
+ },
+ open: function(id, chunkIdx) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.push(id);
+ }
+ if (connectionManager.available()) {
+ if (chunkIdx == null) {
+ connectionManager._waiting.pop();
+ connectionManager._open.push(id);
+ } else {
+ (function() {
+ var openChunksEntry = connectionManager._openChunks[id] || [];
+ openChunksEntry.push(chunkIdx);
+ connectionManager._openChunks[id] = openChunksEntry;
+ })();
+ }
+ return true;
+ }
+ return false;
+ },
+ reset: function() {
+ connectionManager._waiting = [];
+ connectionManager._open = [];
+ }
+ }, simple = {
+ send: function(id, name) {
+ handler._getFileState(id).loaded = 0;
+ log("Sending simple upload request for " + id);
+ handler.uploadFile(id).then(function(response, optXhr) {
+ log("Simple upload request succeeded for " + id);
+ var responseToReport = upload.normalizeResponse(response, true), size = options.getSize(id);
+ options.onProgress(id, name, size, size);
+ upload.maybeNewUuid(id, responseToReport);
+ upload.cleanup(id, responseToReport, optXhr);
+ }, function(response, optXhr) {
+ log("Simple upload request failed for " + id);
+ var responseToReport = upload.normalizeResponse(response, false);
+ if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {
+ upload.cleanup(id, responseToReport, optXhr);
+ }
+ });
+ }
+ }, upload = {
+ cancel: function(id) {
+ log("Cancelling " + id);
+ options.paramsStore.remove(id);
+ connectionManager.free(id);
+ },
+ cleanup: function(id, response, optXhr) {
+ var name = options.getName(id);
+ options.onComplete(id, name, response, optXhr);
+ if (handler._getFileState(id)) {
+ handler._clearXhrs && handler._clearXhrs(id);
+ }
+ connectionManager.free(id);
+ },
+ getProxyOrBlob: function(id) {
+ return handler.getProxy && handler.getProxy(id) || handler.getFile && handler.getFile(id);
+ },
+ initHandler: function() {
+ var handlerType = namespace ? qq[namespace] : qq.traditional, handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? "Xhr" : "Form";
+ handler = new handlerType[handlerModuleSubtype + "UploadHandler"](options, {
+ getDataByUuid: options.getDataByUuid,
+ getName: options.getName,
+ getSize: options.getSize,
+ getUuid: options.getUuid,
+ log: log,
+ onCancel: options.onCancel,
+ onProgress: options.onProgress,
+ onUuidChanged: options.onUuidChanged
+ });
+ if (handler._removeExpiredChunkingRecords) {
+ handler._removeExpiredChunkingRecords();
+ }
+ },
+ isDeferredEligibleForUpload: function(id) {
+ return options.isQueued(id);
+ },
+ maybeDefer: function(id, blob) {
+ if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {
+ options.onUploadPrep(id);
+ log("Attempting to generate a blob on-demand for " + id);
+ blob.create().then(function(generatedBlob) {
+ log("Generated an on-demand blob for " + id);
+ handler.updateBlob(id, generatedBlob);
+ options.setSize(id, generatedBlob.size);
+ handler.reevaluateChunking(id);
+ upload.maybeSendDeferredFiles(id);
+ }, function(errorMessage) {
+ var errorResponse = {};
+ if (errorMessage) {
+ errorResponse.error = errorMessage;
+ }
+ log(qq.format("Failed to generate blob for ID {}. Error message: {}.", id, errorMessage), "error");
+ options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);
+ upload.maybeSendDeferredFiles(id);
+ connectionManager.free(id);
+ });
+ } else {
+ return upload.maybeSendDeferredFiles(id);
+ }
+ return false;
+ },
+ maybeSendDeferredFiles: function(id) {
+ var idsInGroup = options.getIdsInProxyGroup(id), uploadedThisId = false;
+ if (idsInGroup && idsInGroup.length) {
+ log("Maybe ready to upload proxy group file " + id);
+ qq.each(idsInGroup, function(idx, idInGroup) {
+ if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {
+ uploadedThisId = idInGroup === id;
+ upload.now(idInGroup);
+ } else if (upload.isDeferredEligibleForUpload(idInGroup)) {
+ return false;
+ }
+ });
+ } else {
+ uploadedThisId = true;
+ upload.now(id);
+ }
+ return uploadedThisId;
+ },
+ maybeNewUuid: function(id, response) {
+ if (response.newUuid !== undefined) {
+ options.onUuidChanged(id, response.newUuid);
+ }
+ },
+ normalizeResponse: function(originalResponse, successful) {
+ var response = originalResponse;
+ if (!qq.isObject(originalResponse)) {
+ response = {};
+ if (qq.isString(originalResponse) && !successful) {
+ response.error = originalResponse;
+ }
+ }
+ response.success = successful;
+ return response;
+ },
+ now: function(id) {
+ var name = options.getName(id);
+ if (!controller.isValid(id)) {
+ throw new qq.Error(id + " is not a valid file ID to upload!");
+ }
+ options.onUpload(id, name);
+ if (chunkingPossible && handler._shouldChunkThisFile(id)) {
+ chunked.sendNext(id);
+ } else {
+ simple.send(id, name);
+ }
+ },
+ start: function(id) {
+ var blobToUpload = upload.getProxyOrBlob(id);
+ if (blobToUpload) {
+ return upload.maybeDefer(id, blobToUpload);
+ } else {
+ upload.now(id);
+ return true;
+ }
+ }
+ };
+ qq.extend(this, {
+ add: function(id, file) {
+ handler.add.apply(this, arguments);
+ },
+ upload: function(id) {
+ if (connectionManager.open(id)) {
+ return upload.start(id);
+ }
+ return false;
+ },
+ retry: function(id) {
+ if (concurrentChunkingPossible) {
+ handler._getFileState(id).temp.ignoreFailure = false;
+ }
+ if (connectionManager.isUsingConnection(id)) {
+ return upload.start(id);
+ } else {
+ return controller.upload(id);
+ }
+ },
+ cancel: function(id) {
+ var cancelRetVal = handler.cancel(id);
+ if (qq.isGenericPromise(cancelRetVal)) {
+ cancelRetVal.then(function() {
+ upload.cancel(id);
+ });
+ } else if (cancelRetVal !== false) {
+ upload.cancel(id);
+ }
+ },
+ cancelAll: function() {
+ var waitingOrConnected = connectionManager.getWaitingOrConnected(), i;
+ if (waitingOrConnected.length) {
+ for (i = waitingOrConnected.length - 1; i >= 0; i--) {
+ controller.cancel(waitingOrConnected[i]);
+ }
+ }
+ connectionManager.reset();
+ },
+ getFile: function(id) {
+ if (handler.getProxy && handler.getProxy(id)) {
+ return handler.getProxy(id).referenceBlob;
+ }
+ return handler.getFile && handler.getFile(id);
+ },
+ isProxied: function(id) {
+ return !!(handler.getProxy && handler.getProxy(id));
+ },
+ getInput: function(id) {
+ if (handler.getInput) {
+ return handler.getInput(id);
+ }
+ },
+ reset: function() {
+ log("Resetting upload handler");
+ controller.cancelAll();
+ connectionManager.reset();
+ handler.reset();
+ },
+ expunge: function(id) {
+ if (controller.isValid(id)) {
+ return handler.expunge(id);
+ }
+ },
+ isValid: function(id) {
+ return handler.isValid(id);
+ },
+ getResumableFilesData: function() {
+ if (handler.getResumableFilesData) {
+ return handler.getResumableFilesData();
+ }
+ return [];
+ },
+ getThirdPartyFileId: function(id) {
+ if (controller.isValid(id)) {
+ return handler.getThirdPartyFileId(id);
+ }
+ },
+ pause: function(id) {
+ if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {
+ connectionManager.free(id);
+ handler.moveInProgressToRemaining(id);
+ return true;
+ }
+ return false;
+ },
+ isResumable: function(id) {
+ return !!handler.isResumable && handler.isResumable(id);
+ }
+ });
+ qq.extend(options, o);
+ log = options.log;
+ chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;
+ concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;
+ preventRetryResponse = function() {
+ var response = {};
+ response[options.preventRetryParam] = true;
+ return response;
+ }();
+ upload.initHandler();
+ };
+ qq.WindowReceiveMessage = function(o) {
+ "use strict";
+ var options = {
+ log: function(message, level) {}
+ }, callbackWrapperDetachers = {};
+ qq.extend(options, o);
+ qq.extend(this, {
+ receiveMessage: function(id, callback) {
+ var onMessageCallbackWrapper = function(event) {
+ callback(event.data);
+ };
+ if (window.postMessage) {
+ callbackWrapperDetachers[id] = qq(window).attach("message", onMessageCallbackWrapper);
+ } else {
+ log("iframe message passing not supported in this browser!", "error");
+ }
+ },
+ stopReceivingMessages: function(id) {
+ if (window.postMessage) {
+ var detacher = callbackWrapperDetachers[id];
+ if (detacher) {
+ detacher();
+ }
+ }
+ }
+ });
+ };
+ qq.FormUploadHandler = function(spec) {
+ "use strict";
+ var options = spec.options, handler = this, proxy = spec.proxy, formHandlerInstanceId = qq.getUniqueId(), onloadCallbacks = {}, detachLoadEvents = {}, postMessageCallbackTimers = {}, isCors = options.isCors, inputName = options.inputName, getUuid = proxy.getUuid, log = proxy.log, corsMessageReceiver = new qq.WindowReceiveMessage({
+ log: log
+ });
+ function expungeFile(id) {
+ delete detachLoadEvents[id];
+ if (isCors) {
+ clearTimeout(postMessageCallbackTimers[id]);
+ delete postMessageCallbackTimers[id];
+ corsMessageReceiver.stopReceivingMessages(id);
+ }
+ var iframe = document.getElementById(handler._getIframeName(id));
+ if (iframe) {
+ iframe.setAttribute("src", "javascript:false;");
+ qq(iframe).remove();
+ }
+ }
+ function getFileIdForIframeName(iframeName) {
+ return iframeName.split("_")[0];
+ }
+ function initIframeForUpload(name) {
+ var iframe = qq.toElement("");
+ iframe.setAttribute("id", name);
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+ return iframe;
+ }
+ function registerPostMessageCallback(iframe, callback) {
+ var iframeName = iframe.id, fileId = getFileIdForIframeName(iframeName), uuid = getUuid(fileId);
+ onloadCallbacks[uuid] = callback;
+ detachLoadEvents[fileId] = qq(iframe).attach("load", function() {
+ if (handler.getInput(fileId)) {
+ log("Received iframe load event for CORS upload request (iframe name " + iframeName + ")");
+ postMessageCallbackTimers[iframeName] = setTimeout(function() {
+ var errorMessage = "No valid message received from loaded iframe for iframe name " + iframeName;
+ log(errorMessage, "error");
+ callback({
+ error: errorMessage
+ });
+ }, 1e3);
+ }
+ });
+ corsMessageReceiver.receiveMessage(iframeName, function(message) {
+ log("Received the following window message: '" + message + "'");
+ var fileId = getFileIdForIframeName(iframeName), response = handler._parseJsonResponse(message), uuid = response.uuid, onloadCallback;
+ if (uuid && onloadCallbacks[uuid]) {
+ log("Handling response for iframe name " + iframeName);
+ clearTimeout(postMessageCallbackTimers[iframeName]);
+ delete postMessageCallbackTimers[iframeName];
+ handler._detachLoadEvent(iframeName);
+ onloadCallback = onloadCallbacks[uuid];
+ delete onloadCallbacks[uuid];
+ corsMessageReceiver.stopReceivingMessages(iframeName);
+ onloadCallback(response);
+ } else if (!uuid) {
+ log("'" + message + "' does not contain a UUID - ignoring.");
+ }
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, fileInput) {
+ super_.add(id, {
+ input: fileInput
+ });
+ fileInput.setAttribute("name", inputName);
+ if (fileInput.parentNode) {
+ qq(fileInput).remove();
+ }
+ },
+ expunge: function(id) {
+ expungeFile(id);
+ super_.expunge(id);
+ },
+ isValid: function(id) {
+ return super_.isValid(id) && handler._getFileState(id).input !== undefined;
+ }
+ };
+ });
+ qq.extend(this, {
+ getInput: function(id) {
+ return handler._getFileState(id).input;
+ },
+ _attachLoadEvent: function(iframe, callback) {
+ var responseDescriptor;
+ if (isCors) {
+ registerPostMessageCallback(iframe, callback);
+ } else {
+ detachLoadEvents[iframe.id] = qq(iframe).attach("load", function() {
+ log("Received response for " + iframe.id);
+ if (!iframe.parentNode) {
+ return;
+ }
+ try {
+ if (iframe.contentDocument && iframe.contentDocument.body && iframe.contentDocument.body.innerHTML == "false") {
+ return;
+ }
+ } catch (error) {
+ log("Error when attempting to access iframe during handling of upload response (" + error.message + ")", "error");
+ responseDescriptor = {
+ success: false
+ };
+ }
+ callback(responseDescriptor);
+ });
+ }
+ },
+ _createIframe: function(id) {
+ var iframeName = handler._getIframeName(id);
+ return initIframeForUpload(iframeName);
+ },
+ _detachLoadEvent: function(id) {
+ if (detachLoadEvents[id] !== undefined) {
+ detachLoadEvents[id]();
+ delete detachLoadEvents[id];
+ }
+ },
+ _getIframeName: function(fileId) {
+ return fileId + "_" + formHandlerInstanceId;
+ },
+ _initFormForUpload: function(spec) {
+ var method = spec.method, endpoint = spec.endpoint, params = spec.params, paramsInBody = spec.paramsInBody, targetName = spec.targetName, form = qq.toElement(" "), url = endpoint;
+ if (paramsInBody) {
+ qq.obj2Inputs(params, form);
+ } else {
+ url = qq.obj2url(params, endpoint);
+ }
+ form.setAttribute("action", url);
+ form.setAttribute("target", targetName);
+ form.style.display = "none";
+ document.body.appendChild(form);
+ return form;
+ },
+ _parseJsonResponse: function(innerHtmlOrMessage) {
+ var response = {};
+ try {
+ response = qq.parseJson(innerHtmlOrMessage);
+ } catch (error) {
+ log("Error when attempting to parse iframe upload response (" + error.message + ")", "error");
+ }
+ return response;
+ }
+ });
+ };
+ qq.XhrUploadHandler = function(spec) {
+ "use strict";
+ var handler = this, namespace = spec.options.namespace, proxy = spec.proxy, chunking = spec.options.chunking, resume = spec.options.resume, chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking, resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume, getName = proxy.getName, getSize = proxy.getSize, getUuid = proxy.getUuid, getEndpoint = proxy.getEndpoint, getDataByUuid = proxy.getDataByUuid, onUuidChanged = proxy.onUuidChanged, onProgress = proxy.onProgress, log = proxy.log;
+ function abort(id) {
+ qq.each(handler._getXhrs(id), function(xhrId, xhr) {
+ var ajaxRequester = handler._getAjaxRequester(id, xhrId);
+ xhr.onreadystatechange = null;
+ xhr.upload.onprogress = null;
+ xhr.abort();
+ ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);
+ });
+ }
+ qq.extend(this, new qq.UploadHandler(spec));
+ qq.override(this, function(super_) {
+ return {
+ add: function(id, blobOrProxy) {
+ if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {
+ super_.add(id, {
+ file: blobOrProxy
+ });
+ } else if (blobOrProxy instanceof qq.BlobProxy) {
+ super_.add(id, {
+ proxy: blobOrProxy
+ });
+ } else {
+ throw new Error("Passed obj is not a File, Blob, or proxy");
+ }
+ handler._initTempState(id);
+ resumeEnabled && handler._maybePrepareForResume(id);
+ },
+ expunge: function(id) {
+ abort(id);
+ handler._maybeDeletePersistedChunkData(id);
+ handler._clearXhrs(id);
+ super_.expunge(id);
+ }
+ };
+ });
+ qq.extend(this, {
+ clearCachedChunk: function(id, chunkIdx) {
+ delete handler._getFileState(id).temp.cachedChunks[chunkIdx];
+ },
+ clearXhr: function(id, chunkIdx) {
+ var tempState = handler._getFileState(id).temp;
+ if (tempState.xhrs) {
+ delete tempState.xhrs[chunkIdx];
+ }
+ if (tempState.ajaxRequesters) {
+ delete tempState.ajaxRequesters[chunkIdx];
+ }
+ },
+ finalizeChunks: function(id, responseParser) {
+ var lastChunkIdx = handler._getTotalChunks(id) - 1, xhr = handler._getXhr(id, lastChunkIdx);
+ if (responseParser) {
+ return new qq.Promise().success(responseParser(xhr), xhr);
+ }
+ return new qq.Promise().success({}, xhr);
+ },
+ getFile: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).file;
+ },
+ getProxy: function(id) {
+ return handler.isValid(id) && handler._getFileState(id).proxy;
+ },
+ getResumableFilesData: function() {
+ var resumableFilesData = [];
+ handler._iterateResumeRecords(function(key, uploadData) {
+ handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);
+ var data = {
+ name: uploadData.name,
+ remaining: uploadData.chunking.remaining,
+ size: uploadData.size,
+ uuid: uploadData.uuid
+ };
+ if (uploadData.key) {
+ data.key = uploadData.key;
+ }
+ resumableFilesData.push(data);
+ });
+ return resumableFilesData;
+ },
+ isResumable: function(id) {
+ return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;
+ },
+ moveInProgressToRemaining: function(id, optInProgress, optRemaining) {
+ var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress, remaining = optRemaining || handler._getFileState(id).chunking.remaining;
+ if (inProgress) {
+ log(qq.format("Moving these chunks from in-progress {}, to remaining.", JSON.stringify(inProgress)));
+ inProgress.reverse();
+ qq.each(inProgress, function(idx, chunkIdx) {
+ remaining.unshift(chunkIdx);
+ });
+ inProgress.length = 0;
+ }
+ },
+ pause: function(id) {
+ if (handler.isValid(id)) {
+ log(qq.format("Aborting XHR upload for {} '{}' due to pause instruction.", id, getName(id)));
+ handler._getFileState(id).paused = true;
+ abort(id);
+ return true;
+ }
+ },
+ reevaluateChunking: function(id) {
+ if (chunking && handler.isValid(id)) {
+ var state = handler._getFileState(id), totalChunks, i;
+ delete state.chunking;
+ state.chunking = {};
+ totalChunks = handler._getTotalChunks(id);
+ if (totalChunks > 1 || chunking.mandatory) {
+ state.chunking.enabled = true;
+ state.chunking.parts = totalChunks;
+ state.chunking.remaining = [];
+ for (i = 0; i < totalChunks; i++) {
+ state.chunking.remaining.push(i);
+ }
+ handler._initTempState(id);
+ } else {
+ state.chunking.enabled = false;
+ }
+ }
+ },
+ updateBlob: function(id, newBlob) {
+ if (handler.isValid(id)) {
+ handler._getFileState(id).file = newBlob;
+ }
+ },
+ _clearXhrs: function(id) {
+ var tempState = handler._getFileState(id).temp;
+ qq.each(tempState.ajaxRequesters, function(chunkId) {
+ delete tempState.ajaxRequesters[chunkId];
+ });
+ qq.each(tempState.xhrs, function(chunkId) {
+ delete tempState.xhrs[chunkId];
+ });
+ },
+ _createXhr: function(id, optChunkIdx) {
+ return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());
+ },
+ _getAjaxRequester: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];
+ },
+ _getChunkData: function(id, chunkIndex) {
+ var chunkSize = chunking.partSize, fileSize = getSize(id), fileOrBlob = handler.getFile(id), startBytes = chunkSize * chunkIndex, endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize, totalChunks = handler._getTotalChunks(id), cachedChunks = this._getFileState(id).temp.cachedChunks, blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);
+ cachedChunks[chunkIndex] = blob;
+ return {
+ part: chunkIndex,
+ start: startBytes,
+ end: endBytes,
+ count: totalChunks,
+ blob: blob,
+ size: endBytes - startBytes
+ };
+ },
+ _getChunkDataForCallback: function(chunkData) {
+ return {
+ partIndex: chunkData.part,
+ startByte: chunkData.start + 1,
+ endByte: chunkData.end,
+ totalParts: chunkData.count
+ };
+ },
+ _getLocalStorageId: function(id) {
+ var formatVersion = "5.0", name = getName(id), size = getSize(id), chunkSize = chunking.partSize, endpoint = getEndpoint(id);
+ return qq.format("qq{}resume{}-{}-{}-{}-{}", namespace, formatVersion, name, size, chunkSize, endpoint);
+ },
+ _getMimeType: function(id) {
+ return handler.getFile(id).type;
+ },
+ _getPersistableData: function(id) {
+ return handler._getFileState(id).chunking;
+ },
+ _getTotalChunks: function(id) {
+ if (chunking) {
+ var fileSize = getSize(id), chunkSize = chunking.partSize;
+ return Math.ceil(fileSize / chunkSize);
+ }
+ },
+ _getXhr: function(id, optChunkIdx) {
+ var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;
+ return handler._getFileState(id).temp.xhrs[chunkIdx];
+ },
+ _getXhrs: function(id) {
+ return handler._getFileState(id).temp.xhrs;
+ },
+ _iterateResumeRecords: function(callback) {
+ if (resumeEnabled) {
+ qq.each(localStorage, function(key, item) {
+ if (key.indexOf(qq.format("qq{}resume", namespace)) === 0) {
+ var uploadData = JSON.parse(item);
+ callback(key, uploadData);
+ }
+ });
+ }
+ },
+ _initTempState: function(id) {
+ handler._getFileState(id).temp = {
+ ajaxRequesters: {},
+ chunkProgress: {},
+ xhrs: {},
+ cachedChunks: {}
+ };
+ },
+ _markNotResumable: function(id) {
+ handler._getFileState(id).notResumable = true;
+ },
+ _maybeDeletePersistedChunkData: function(id) {
+ var localStorageId;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ if (localStorageId && localStorage.getItem(localStorageId)) {
+ localStorage.removeItem(localStorageId);
+ return true;
+ }
+ }
+ return false;
+ },
+ _maybePrepareForResume: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && state.key === undefined) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = localStorage.getItem(localStorageId);
+ if (persistedData) {
+ persistedData = JSON.parse(persistedData);
+ if (getDataByUuid(persistedData.uuid)) {
+ handler._markNotResumable(id);
+ } else {
+ log(qq.format("Identified file with ID {} and name of {} as resumable.", id, getName(id)));
+ onUuidChanged(id, persistedData.uuid);
+ state.key = persistedData.key;
+ state.chunking = persistedData.chunking;
+ state.loaded = persistedData.loaded;
+ state.attemptingResume = true;
+ handler.moveInProgressToRemaining(id);
+ }
+ }
+ }
+ },
+ _maybePersistChunkedState: function(id) {
+ var state = handler._getFileState(id), localStorageId, persistedData;
+ if (resumeEnabled && handler.isResumable(id)) {
+ localStorageId = handler._getLocalStorageId(id);
+ persistedData = {
+ name: getName(id),
+ size: getSize(id),
+ uuid: getUuid(id),
+ key: state.key,
+ chunking: state.chunking,
+ loaded: state.loaded,
+ lastUpdated: Date.now()
+ };
+ try {
+ localStorage.setItem(localStorageId, JSON.stringify(persistedData));
+ } catch (error) {
+ log(qq.format("Unable to save resume data for '{}' due to error: '{}'.", id, error.toString()), "warn");
+ }
+ }
+ },
+ _registerProgressHandler: function(id, chunkIdx, chunkSize) {
+ var xhr = handler._getXhr(id, chunkIdx), name = getName(id), progressCalculator = {
+ simple: function(loaded, total) {
+ var fileSize = getSize(id);
+ if (loaded === total) {
+ onProgress(id, name, fileSize, fileSize);
+ } else {
+ onProgress(id, name, loaded >= fileSize ? fileSize - 1 : loaded, fileSize);
+ }
+ },
+ chunked: function(loaded, total) {
+ var chunkProgress = handler._getFileState(id).temp.chunkProgress, totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded, loadedForRequest = loaded, totalForRequest = total, totalFileSize = getSize(id), estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize), totalLoadedForFile = totalSuccessfullyLoadedForFile;
+ chunkProgress[chunkIdx] = estActualChunkLoaded;
+ qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {
+ totalLoadedForFile += chunkLoaded;
+ });
+ onProgress(id, name, totalLoadedForFile, totalFileSize);
+ }
+ };
+ xhr.upload.onprogress = function(e) {
+ if (e.lengthComputable) {
+ var type = chunkSize == null ? "simple" : "chunked";
+ progressCalculator[type](e.loaded, e.total);
+ }
+ };
+ },
+ _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {
+ var xhrsId = optChunkIdx == null ? -1 : optChunkIdx, tempState = handler._getFileState(id).temp;
+ tempState.xhrs = tempState.xhrs || {};
+ tempState.ajaxRequesters = tempState.ajaxRequesters || {};
+ tempState.xhrs[xhrsId] = xhr;
+ if (optAjaxRequester) {
+ tempState.ajaxRequesters[xhrsId] = optAjaxRequester;
+ }
+ return xhr;
+ },
+ _removeExpiredChunkingRecords: function() {
+ var expirationDays = resume.recordsExpireIn;
+ handler._iterateResumeRecords(function(key, uploadData) {
+ var expirationDate = new Date(uploadData.lastUpdated);
+ expirationDate.setDate(expirationDate.getDate() + expirationDays);
+ if (expirationDate.getTime() <= Date.now()) {
+ log("Removing expired resume record with key " + key);
+ localStorage.removeItem(key);
+ }
+ });
+ },
+ _shouldChunkThisFile: function(id) {
+ var state = handler._getFileState(id);
+ if (!state.chunking) {
+ handler.reevaluateChunking(id);
+ }
+ return state.chunking.enabled;
+ }
+ });
+ };
+ qq.DeleteFileAjaxRequester = function(o) {
+ "use strict";
+ var requester, options = {
+ method: "DELETE",
+ uuidParamName: "qquuid",
+ endpointStore: {},
+ maxConnections: 3,
+ customHeaders: function(id) {
+ return {};
+ },
+ paramsStore: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ log: function(str, level) {},
+ onDelete: function(id) {},
+ onDeleteComplete: function(id, xhrOrXdr, isError) {}
+ };
+ qq.extend(options, o);
+ function getMandatedParams() {
+ if (options.method.toUpperCase() === "POST") {
+ return {
+ _method: "DELETE"
+ };
+ }
+ return {};
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "POST", "DELETE" ],
+ method: options.method,
+ endpointStore: options.endpointStore,
+ paramsStore: options.paramsStore,
+ mandatedParams: getMandatedParams(),
+ maxConnections: options.maxConnections,
+ customHeaders: function(id) {
+ return options.customHeaders.get(id);
+ },
+ log: options.log,
+ onSend: options.onDelete,
+ onComplete: options.onDeleteComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ sendDelete: function(id, uuid, additionalMandatedParams) {
+ var additionalOptions = additionalMandatedParams || {};
+ options.log("Submitting delete file request for " + id);
+ if (options.method === "DELETE") {
+ requester.initTransport(id).withPath(uuid).withParams(additionalOptions).send();
+ } else {
+ additionalOptions[options.uuidParamName] = uuid;
+ requester.initTransport(id).withParams(additionalOptions).send();
+ }
+ }
+ });
+ };
+ (function() {
+ function detectSubsampling(img) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, canvas = document.createElement("canvas"), ctx;
+ if (iw * ih > 1024 * 1024) {
+ canvas.width = canvas.height = 1;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, -iw + 1, 0);
+ return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+ } else {
+ return false;
+ }
+ }
+ function detectVerticalSquash(img, iw, ih) {
+ var canvas = document.createElement("canvas"), sy = 0, ey = ih, py = ih, ctx, data, alpha, ratio;
+ canvas.width = 1;
+ canvas.height = ih;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(img, 0, 0);
+ data = ctx.getImageData(0, 0, 1, ih).data;
+ while (py > sy) {
+ alpha = data[(py - 1) * 4 + 3];
+ if (alpha === 0) {
+ ey = py;
+ } else {
+ sy = py;
+ }
+ py = ey + sy >> 1;
+ }
+ ratio = py / ih;
+ return ratio === 0 ? 1 : ratio;
+ }
+ function renderImageToDataURL(img, blob, options, doSquash) {
+ var canvas = document.createElement("canvas"), mime = options.mime || "image/jpeg", promise = new qq.Promise();
+ renderImageToCanvas(img, blob, canvas, options, doSquash).then(function() {
+ promise.success(canvas.toDataURL(mime, options.quality || .8));
+ });
+ return promise;
+ }
+ function maybeCalculateDownsampledDimensions(spec) {
+ var maxPixels = 5241e3;
+ if (!qq.ios()) {
+ throw new qq.Error("Downsampled dimensions can only be reliably calculated for iOS!");
+ }
+ if (spec.origHeight * spec.origWidth > maxPixels) {
+ return {
+ newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),
+ newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))
+ };
+ }
+ }
+ function renderImageToCanvas(img, blob, canvas, options, doSquash) {
+ var iw = img.naturalWidth, ih = img.naturalHeight, width = options.width, height = options.height, ctx = canvas.getContext("2d"), promise = new qq.Promise(), modifiedDimensions;
+ ctx.save();
+ if (options.resize) {
+ return renderImageToCanvasWithCustomResizer({
+ blob: blob,
+ canvas: canvas,
+ image: img,
+ imageHeight: ih,
+ imageWidth: iw,
+ orientation: options.orientation,
+ resize: options.resize,
+ targetHeight: height,
+ targetWidth: width
+ });
+ }
+ if (!qq.supportedFeatures.unlimitedScaledImageSize) {
+ modifiedDimensions = maybeCalculateDownsampledDimensions({
+ origWidth: width,
+ origHeight: height
+ });
+ if (modifiedDimensions) {
+ qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h", width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight), "warn");
+ width = modifiedDimensions.newWidth;
+ height = modifiedDimensions.newHeight;
+ }
+ }
+ transformCoordinate(canvas, width, height, options.orientation);
+ if (qq.ios()) {
+ (function() {
+ if (detectSubsampling(img)) {
+ iw /= 2;
+ ih /= 2;
+ }
+ var d = 1024, tmpCanvas = document.createElement("canvas"), vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1, dw = Math.ceil(d * width / iw), dh = Math.ceil(d * height / ih / vertSquashRatio), sy = 0, dy = 0, tmpCtx, sx, dx;
+ tmpCanvas.width = tmpCanvas.height = d;
+ tmpCtx = tmpCanvas.getContext("2d");
+ while (sy < ih) {
+ sx = 0;
+ dx = 0;
+ while (sx < iw) {
+ tmpCtx.clearRect(0, 0, d, d);
+ tmpCtx.drawImage(img, -sx, -sy);
+ ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);
+ sx += d;
+ dx += dw;
+ }
+ sy += d;
+ dy += dh;
+ }
+ ctx.restore();
+ tmpCanvas = tmpCtx = null;
+ })();
+ } else {
+ ctx.drawImage(img, 0, 0, width, height);
+ }
+ canvas.qqImageRendered && canvas.qqImageRendered();
+ promise.success();
+ return promise;
+ }
+ function renderImageToCanvasWithCustomResizer(resizeInfo) {
+ var blob = resizeInfo.blob, image = resizeInfo.image, imageHeight = resizeInfo.imageHeight, imageWidth = resizeInfo.imageWidth, orientation = resizeInfo.orientation, promise = new qq.Promise(), resize = resizeInfo.resize, sourceCanvas = document.createElement("canvas"), sourceCanvasContext = sourceCanvas.getContext("2d"), targetCanvas = resizeInfo.canvas, targetHeight = resizeInfo.targetHeight, targetWidth = resizeInfo.targetWidth;
+ transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);
+ targetCanvas.height = targetHeight;
+ targetCanvas.width = targetWidth;
+ sourceCanvasContext.drawImage(image, 0, 0);
+ resize({
+ blob: blob,
+ height: targetHeight,
+ image: image,
+ sourceCanvas: sourceCanvas,
+ targetCanvas: targetCanvas,
+ width: targetWidth
+ }).then(function success() {
+ targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();
+ promise.success();
+ }, promise.failure);
+ return promise;
+ }
+ function transformCoordinate(canvas, width, height, orientation) {
+ switch (orientation) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ canvas.width = height;
+ canvas.height = width;
+ break;
+
+ default:
+ canvas.width = width;
+ canvas.height = height;
+ }
+ var ctx = canvas.getContext("2d");
+ switch (orientation) {
+ case 2:
+ ctx.translate(width, 0);
+ ctx.scale(-1, 1);
+ break;
+
+ case 3:
+ ctx.translate(width, height);
+ ctx.rotate(Math.PI);
+ break;
+
+ case 4:
+ ctx.translate(0, height);
+ ctx.scale(1, -1);
+ break;
+
+ case 5:
+ ctx.rotate(.5 * Math.PI);
+ ctx.scale(1, -1);
+ break;
+
+ case 6:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(0, -height);
+ break;
+
+ case 7:
+ ctx.rotate(.5 * Math.PI);
+ ctx.translate(width, -height);
+ ctx.scale(-1, 1);
+ break;
+
+ case 8:
+ ctx.rotate(-.5 * Math.PI);
+ ctx.translate(-width, 0);
+ break;
+
+ default:
+ break;
+ }
+ }
+ function MegaPixImage(srcImage, errorCallback) {
+ var self = this;
+ if (window.Blob && srcImage instanceof Blob) {
+ (function() {
+ var img = new Image(), URL = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (!URL) {
+ throw Error("No createObjectURL function found to create blob url");
+ }
+ img.src = URL.createObjectURL(srcImage);
+ self.blob = srcImage;
+ srcImage = img;
+ })();
+ }
+ if (!srcImage.naturalWidth && !srcImage.naturalHeight) {
+ srcImage.onload = function() {
+ var listeners = self.imageLoadListeners;
+ if (listeners) {
+ self.imageLoadListeners = null;
+ setTimeout(function() {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i]();
+ }
+ }, 0);
+ }
+ };
+ srcImage.onerror = errorCallback;
+ this.imageLoadListeners = [];
+ }
+ this.srcImage = srcImage;
+ }
+ MegaPixImage.prototype.render = function(target, options) {
+ options = options || {};
+ var self = this, imgWidth = this.srcImage.naturalWidth, imgHeight = this.srcImage.naturalHeight, width = options.width, height = options.height, maxWidth = options.maxWidth, maxHeight = options.maxHeight, doSquash = !this.blob || this.blob.type === "image/jpeg", tagName = target.tagName.toLowerCase(), opt;
+ if (this.imageLoadListeners) {
+ this.imageLoadListeners.push(function() {
+ self.render(target, options);
+ });
+ return;
+ }
+ if (width && !height) {
+ height = imgHeight * width / imgWidth << 0;
+ } else if (height && !width) {
+ width = imgWidth * height / imgHeight << 0;
+ } else {
+ width = imgWidth;
+ height = imgHeight;
+ }
+ if (maxWidth && width > maxWidth) {
+ width = maxWidth;
+ height = imgHeight * width / imgWidth << 0;
+ }
+ if (maxHeight && height > maxHeight) {
+ height = maxHeight;
+ width = imgWidth * height / imgHeight << 0;
+ }
+ opt = {
+ width: width,
+ height: height
+ }, qq.each(options, function(optionsKey, optionsValue) {
+ opt[optionsKey] = optionsValue;
+ });
+ if (tagName === "img") {
+ (function() {
+ var oldTargetSrc = target.src;
+ renderImageToDataURL(self.srcImage, self.blob, opt, doSquash).then(function(dataUri) {
+ target.src = dataUri;
+ oldTargetSrc === target.src && target.onload();
+ });
+ })();
+ } else if (tagName === "canvas") {
+ renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);
+ }
+ if (typeof this.onrender === "function") {
+ this.onrender(target);
+ }
+ };
+ qq.MegaPixImage = MegaPixImage;
+ })();
+ qq.ImageGenerator = function(log) {
+ "use strict";
+ function isImg(el) {
+ return el.tagName.toLowerCase() === "img";
+ }
+ function isCanvas(el) {
+ return el.tagName.toLowerCase() === "canvas";
+ }
+ function isImgCorsSupported() {
+ return new Image().crossOrigin !== undefined;
+ }
+ function isCanvasSupported() {
+ var canvas = document.createElement("canvas");
+ return canvas.getContext && canvas.getContext("2d");
+ }
+ function determineMimeOfFileName(nameWithPath) {
+ var pathSegments = nameWithPath.split("/"), name = pathSegments[pathSegments.length - 1].split("?")[0], extension = qq.getExtension(name);
+ extension = extension && extension.toLowerCase();
+ switch (extension) {
+ case "jpeg":
+ case "jpg":
+ return "image/jpeg";
+
+ case "png":
+ return "image/png";
+
+ case "bmp":
+ return "image/bmp";
+
+ case "gif":
+ return "image/gif";
+
+ case "tiff":
+ case "tif":
+ return "image/tiff";
+ }
+ }
+ function isCrossOrigin(url) {
+ var targetAnchor = document.createElement("a"), targetProtocol, targetHostname, targetPort;
+ targetAnchor.href = url;
+ targetProtocol = targetAnchor.protocol;
+ targetPort = targetAnchor.port;
+ targetHostname = targetAnchor.hostname;
+ if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {
+ return true;
+ }
+ if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {
+ return true;
+ }
+ if (targetPort !== window.location.port && !qq.ie()) {
+ return true;
+ }
+ return false;
+ }
+ function registerImgLoadListeners(img, promise) {
+ img.onload = function() {
+ img.onload = null;
+ img.onerror = null;
+ promise.success(img);
+ };
+ img.onerror = function() {
+ img.onload = null;
+ img.onerror = null;
+ log("Problem drawing thumbnail!", "error");
+ promise.failure(img, "Problem drawing thumbnail!");
+ };
+ }
+ function registerCanvasDrawImageListener(canvas, promise) {
+ canvas.qqImageRendered = function() {
+ promise.success(canvas);
+ };
+ }
+ function registerThumbnailRenderedListener(imgOrCanvas, promise) {
+ var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);
+ if (isImg(imgOrCanvas)) {
+ registerImgLoadListeners(imgOrCanvas, promise);
+ } else if (isCanvas(imgOrCanvas)) {
+ registerCanvasDrawImageListener(imgOrCanvas, promise);
+ } else {
+ promise.failure(imgOrCanvas);
+ log(qq.format("Element container of type {} is not supported!", imgOrCanvas.tagName), "error");
+ }
+ return registered;
+ }
+ function draw(fileOrBlob, container, options) {
+ var drawPreview = new qq.Promise(), identifier = new qq.Identify(fileOrBlob, log), maxSize = options.maxSize, orient = options.orient == null ? true : options.orient, megapixErrorHandler = function() {
+ container.onerror = null;
+ container.onload = null;
+ log("Could not render preview, file may be too large!", "error");
+ drawPreview.failure(container, "Browser cannot render image!");
+ };
+ identifier.isPreviewable().then(function(mime) {
+ var dummyExif = {
+ parse: function() {
+ return new qq.Promise().success();
+ }
+ }, exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif, mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);
+ if (registerThumbnailRenderedListener(container, drawPreview)) {
+ exif.parse().then(function(exif) {
+ var orientation = exif && exif.Orientation;
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ orientation: orientation,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ }, function(failureMsg) {
+ log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", failureMsg));
+ mpImg.render(container, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: mime,
+ resize: options.customResizeFunction
+ });
+ });
+ }
+ }, function() {
+ log("Not previewable");
+ drawPreview.failure(container, "Not previewable");
+ });
+ return drawPreview;
+ }
+ function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {
+ var tempImg = new Image(), tempImgRender = new qq.Promise();
+ registerThumbnailRenderedListener(tempImg, tempImgRender);
+ if (isCrossOrigin(url)) {
+ tempImg.crossOrigin = "anonymous";
+ }
+ tempImg.src = url;
+ tempImgRender.then(function rendered() {
+ registerThumbnailRenderedListener(canvasOrImg, draw);
+ var mpImg = new qq.MegaPixImage(tempImg);
+ mpImg.render(canvasOrImg, {
+ maxWidth: maxSize,
+ maxHeight: maxSize,
+ mime: determineMimeOfFileName(url),
+ resize: customResizeFunction
+ });
+ }, draw.failure);
+ }
+ function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {
+ registerThumbnailRenderedListener(img, draw);
+ qq(img).css({
+ maxWidth: maxSize + "px",
+ maxHeight: maxSize + "px"
+ });
+ img.src = url;
+ }
+ function drawFromUrl(url, container, options) {
+ var draw = new qq.Promise(), scale = options.scale, maxSize = scale ? options.maxSize : null;
+ if (scale && isImg(container)) {
+ if (isCanvasSupported()) {
+ if (isCrossOrigin(url) && !isImgCorsSupported()) {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ } else {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ }
+ } else {
+ drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);
+ }
+ } else if (isCanvas(container)) {
+ drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);
+ } else if (registerThumbnailRenderedListener(container, draw)) {
+ container.src = url;
+ }
+ return draw;
+ }
+ qq.extend(this, {
+ generate: function(fileBlobOrUrl, container, options) {
+ if (qq.isString(fileBlobOrUrl)) {
+ log("Attempting to update thumbnail based on server response.");
+ return drawFromUrl(fileBlobOrUrl, container, options || {});
+ } else {
+ log("Attempting to draw client-side image preview.");
+ return draw(fileBlobOrUrl, container, options || {});
+ }
+ }
+ });
+ this._testing = {};
+ this._testing.isImg = isImg;
+ this._testing.isCanvas = isCanvas;
+ this._testing.isCrossOrigin = isCrossOrigin;
+ this._testing.determineMimeOfFileName = determineMimeOfFileName;
+ };
+ qq.Exif = function(fileOrBlob, log) {
+ "use strict";
+ var TAG_IDS = [ 274 ], TAG_INFO = {
+ 274: {
+ name: "Orientation",
+ bytes: 2
+ }
+ };
+ function parseLittleEndian(hex) {
+ var result = 0, pow = 0;
+ while (hex.length > 0) {
+ result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);
+ hex = hex.substring(2, hex.length);
+ pow += 8;
+ }
+ return result;
+ }
+ function seekToApp1(offset, promise) {
+ var theOffset = offset, thePromise = promise;
+ if (theOffset === undefined) {
+ theOffset = 2;
+ thePromise = new qq.Promise();
+ }
+ qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {
+ var match = /^ffe([0-9])/.exec(hex), segmentLength;
+ if (match) {
+ if (match[1] !== "1") {
+ segmentLength = parseInt(hex.slice(4, 8), 16);
+ seekToApp1(theOffset + segmentLength + 2, thePromise);
+ } else {
+ thePromise.success(theOffset);
+ }
+ } else {
+ thePromise.failure("No EXIF header to be found!");
+ }
+ });
+ return thePromise;
+ }
+ function getApp1Offset() {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {
+ if (hex.indexOf("ffd8") !== 0) {
+ promise.failure("Not a valid JPEG!");
+ } else {
+ seekToApp1().then(function(offset) {
+ promise.success(offset);
+ }, function(error) {
+ promise.failure(error);
+ });
+ }
+ });
+ return promise;
+ }
+ function isLittleEndian(app1Start) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {
+ promise.success(hex === "4949");
+ });
+ return promise;
+ }
+ function getDirEntryCount(app1Start, littleEndian) {
+ var promise = new qq.Promise();
+ qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {
+ if (littleEndian) {
+ return promise.success(parseLittleEndian(hex));
+ } else {
+ promise.success(parseInt(hex, 16));
+ }
+ });
+ return promise;
+ }
+ function getIfd(app1Start, dirEntries) {
+ var offset = app1Start + 20, bytes = dirEntries * 12;
+ return qq.readBlobToHex(fileOrBlob, offset, bytes);
+ }
+ function getDirEntries(ifdHex) {
+ var entries = [], offset = 0;
+ while (offset + 24 <= ifdHex.length) {
+ entries.push(ifdHex.slice(offset, offset + 24));
+ offset += 24;
+ }
+ return entries;
+ }
+ function getTagValues(littleEndian, dirEntries) {
+ var TAG_VAL_OFFSET = 16, tagsToFind = qq.extend([], TAG_IDS), vals = {};
+ qq.each(dirEntries, function(idx, entry) {
+ var idHex = entry.slice(0, 4), id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16), tagsToFindIdx = tagsToFind.indexOf(id), tagValHex, tagName, tagValLength;
+ if (tagsToFindIdx >= 0) {
+ tagName = TAG_INFO[id].name;
+ tagValLength = TAG_INFO[id].bytes;
+ tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + tagValLength * 2);
+ vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);
+ tagsToFind.splice(tagsToFindIdx, 1);
+ }
+ if (tagsToFind.length === 0) {
+ return false;
+ }
+ });
+ return vals;
+ }
+ qq.extend(this, {
+ parse: function() {
+ var parser = new qq.Promise(), onParseFailure = function(message) {
+ log(qq.format("EXIF header parse failed: '{}' ", message));
+ parser.failure(message);
+ };
+ getApp1Offset().then(function(app1Offset) {
+ log(qq.format("Moving forward with EXIF header parsing for '{}'", fileOrBlob.name === undefined ? "blob" : fileOrBlob.name));
+ isLittleEndian(app1Offset).then(function(littleEndian) {
+ log(qq.format("EXIF Byte order is {} endian", littleEndian ? "little" : "big"));
+ getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {
+ log(qq.format("Found {} APP1 directory entries", dirEntryCount));
+ getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {
+ var dirEntries = getDirEntries(ifdHex), tagValues = getTagValues(littleEndian, dirEntries);
+ log("Successfully parsed some EXIF tags");
+ parser.success(tagValues);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ }, onParseFailure);
+ return parser;
+ }
+ });
+ this._testing = {};
+ this._testing.parseLittleEndian = parseLittleEndian;
+ };
+ qq.Identify = function(fileOrBlob, log) {
+ "use strict";
+ function isIdentifiable(magicBytes, questionableBytes) {
+ var identifiable = false, magicBytesEntries = [].concat(magicBytes);
+ qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {
+ if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {
+ identifiable = true;
+ return false;
+ }
+ });
+ return identifiable;
+ }
+ qq.extend(this, {
+ isPreviewable: function() {
+ var self = this, identifier = new qq.Promise(), previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ log(qq.format("Attempting to determine if {} can be rendered in this browser", name));
+ log("First pass: check type attribute of blob object.");
+ if (this.isPreviewableSync()) {
+ log("Second pass: check for magic bytes in file header.");
+ qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {
+ qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {
+ if (isIdentifiable(bytes, hex)) {
+ if (mime !== "image/tiff" || qq.supportedFeatures.tiffPreviews) {
+ previewable = true;
+ identifier.success(mime);
+ }
+ return false;
+ }
+ });
+ log(qq.format("'{}' is {} able to be rendered in this browser", name, previewable ? "" : "NOT"));
+ if (!previewable) {
+ identifier.failure();
+ }
+ }, function() {
+ log("Error reading file w/ name '" + name + "'. Not able to be rendered in this browser.");
+ identifier.failure();
+ });
+ } else {
+ identifier.failure();
+ }
+ return identifier;
+ },
+ isPreviewableSync: function() {
+ var fileMime = fileOrBlob.type, isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0, previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;
+ if (isRecognizedImage) {
+ if (fileMime === "image/tiff") {
+ previewable = qq.supportedFeatures.tiffPreviews;
+ } else {
+ previewable = true;
+ }
+ }
+ !previewable && log(name + " is not previewable in this browser per the blob's type attr");
+ return previewable;
+ }
+ });
+ };
+ qq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {
+ "image/jpeg": "ffd8ff",
+ "image/gif": "474946",
+ "image/png": "89504e",
+ "image/bmp": "424d",
+ "image/tiff": [ "49492a00", "4d4d002a" ]
+ };
+ qq.ImageValidation = function(blob, log) {
+ "use strict";
+ function hasNonZeroLimits(limits) {
+ var atLeastOne = false;
+ qq.each(limits, function(limit, value) {
+ if (value > 0) {
+ atLeastOne = true;
+ return false;
+ }
+ });
+ return atLeastOne;
+ }
+ function getWidthHeight() {
+ var sizeDetermination = new qq.Promise();
+ new qq.Identify(blob, log).isPreviewable().then(function() {
+ var image = new Image(), url = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
+ if (url) {
+ image.onerror = function() {
+ log("Cannot determine dimensions for image. May be too large.", "error");
+ sizeDetermination.failure();
+ };
+ image.onload = function() {
+ sizeDetermination.success({
+ width: this.width,
+ height: this.height
+ });
+ };
+ image.src = url.createObjectURL(blob);
+ } else {
+ log("No createObjectURL function available to generate image URL!", "error");
+ sizeDetermination.failure();
+ }
+ }, sizeDetermination.failure);
+ return sizeDetermination;
+ }
+ function getFailingLimit(limits, dimensions) {
+ var failingLimit;
+ qq.each(limits, function(limitName, limitValue) {
+ if (limitValue > 0) {
+ var limitMatcher = /(max|min)(Width|Height)/.exec(limitName), dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1), actualValue = dimensions[dimensionPropName];
+ switch (limitMatcher[1]) {
+ case "min":
+ if (actualValue < limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+
+ case "max":
+ if (actualValue > limitValue) {
+ failingLimit = limitName;
+ return false;
+ }
+ break;
+ }
+ }
+ });
+ return failingLimit;
+ }
+ this.validate = function(limits) {
+ var validationEffort = new qq.Promise();
+ log("Attempting to validate image.");
+ if (hasNonZeroLimits(limits)) {
+ getWidthHeight().then(function(dimensions) {
+ var failingLimit = getFailingLimit(limits, dimensions);
+ if (failingLimit) {
+ validationEffort.failure(failingLimit);
+ } else {
+ validationEffort.success();
+ }
+ }, validationEffort.success);
+ } else {
+ validationEffort.success();
+ }
+ return validationEffort;
+ };
+ };
+ qq.Session = function(spec) {
+ "use strict";
+ var options = {
+ endpoint: null,
+ params: {},
+ customHeaders: {},
+ cors: {},
+ addFileRecord: function(sessionData) {},
+ log: function(message, level) {}
+ };
+ qq.extend(options, spec, true);
+ function isJsonResponseValid(response) {
+ if (qq.isArray(response)) {
+ return true;
+ }
+ options.log("Session response is not an array.", "error");
+ }
+ function handleFileItems(fileItems, success, xhrOrXdr, promise) {
+ var someItemsIgnored = false;
+ success = success && isJsonResponseValid(fileItems);
+ if (success) {
+ qq.each(fileItems, function(idx, fileItem) {
+ if (fileItem.uuid == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid UUID - ignoring.", idx), "error");
+ } else if (fileItem.name == null) {
+ someItemsIgnored = true;
+ options.log(qq.format("Session response item {} did not include a valid name - ignoring.", idx), "error");
+ } else {
+ try {
+ options.addFileRecord(fileItem);
+ return true;
+ } catch (err) {
+ someItemsIgnored = true;
+ options.log(err.message, "error");
+ }
+ }
+ return false;
+ });
+ }
+ promise[success && !someItemsIgnored ? "success" : "failure"](fileItems, xhrOrXdr);
+ }
+ this.refresh = function() {
+ var refreshEffort = new qq.Promise(), refreshCompleteCallback = function(response, success, xhrOrXdr) {
+ handleFileItems(response, success, xhrOrXdr, refreshEffort);
+ }, requesterOptions = qq.extend({}, options), requester = new qq.SessionAjaxRequester(qq.extend(requesterOptions, {
+ onComplete: refreshCompleteCallback
+ }));
+ requester.queryServer();
+ return refreshEffort;
+ };
+ };
+ qq.SessionAjaxRequester = function(spec) {
+ "use strict";
+ var requester, options = {
+ endpoint: null,
+ customHeaders: {},
+ params: {},
+ cors: {
+ expected: false,
+ sendCredentials: false
+ },
+ onComplete: function(response, success, xhrOrXdr) {},
+ log: function(str, level) {}
+ };
+ qq.extend(options, spec);
+ function onComplete(id, xhrOrXdr, isError) {
+ var response = null;
+ if (xhrOrXdr.responseText != null) {
+ try {
+ response = qq.parseJson(xhrOrXdr.responseText);
+ } catch (err) {
+ options.log("Problem parsing session response: " + err.message, "error");
+ isError = true;
+ }
+ }
+ options.onComplete(response, !isError, xhrOrXdr);
+ }
+ requester = qq.extend(this, new qq.AjaxRequester({
+ acceptHeader: "application/json",
+ validMethods: [ "GET" ],
+ method: "GET",
+ endpointStore: {
+ get: function() {
+ return options.endpoint;
+ }
+ },
+ customHeaders: options.customHeaders,
+ log: options.log,
+ onComplete: onComplete,
+ cors: options.cors
+ }));
+ qq.extend(this, {
+ queryServer: function() {
+ var params = qq.extend({}, options.params);
+ options.log("Session query request.");
+ requester.initTransport("sessionRefresh").withParams(params).withCacheBuster().send();
+ }
+ });
+ };
+ qq.Scaler = function(spec, log) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizer, includeOriginal = spec.sendOriginal, orient = spec.orient, defaultType = spec.defaultType, defaultQuality = spec.defaultQuality / 100, failedToScaleText = spec.failureText, includeExif = spec.includeExif, sizes = this._getSortedSizes(spec.sizes);
+ qq.extend(this, {
+ enabled: qq.supportedFeatures.scaling && sizes.length > 0,
+ getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {
+ var self = this, records = [], originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData, identifier = new qq.Identify(originalBlob, log);
+ if (identifier.isPreviewableSync()) {
+ qq.each(sizes, function(idx, sizeRecord) {
+ var outputType = self._determineOutputType({
+ defaultType: defaultType,
+ requestedType: sizeRecord.type,
+ refType: originalBlob.type
+ });
+ records.push({
+ uuid: qq.getUniqueId(),
+ name: self._getName(originalFileName, {
+ name: sizeRecord.name,
+ type: outputType,
+ refType: originalBlob.type
+ }),
+ blob: new qq.BlobProxy(originalBlob, qq.bind(self._generateScaledImage, self, {
+ customResizeFunction: customResizeFunction,
+ maxSize: sizeRecord.maxSize,
+ orient: orient,
+ type: outputType,
+ quality: defaultQuality,
+ failedText: failedToScaleText,
+ includeExif: includeExif,
+ log: log
+ }))
+ });
+ });
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: includeOriginal ? originalBlob : null
+ });
+ } else {
+ records.push({
+ uuid: originalFileUuid,
+ name: originalFileName,
+ size: originalBlob.size,
+ blob: originalBlob
+ });
+ }
+ return records;
+ },
+ handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {
+ var self = this, buttonId = file.qqButtonId || file.blob && file.blob.qqButtonId, scaledIds = [], originalId = null, addFileToHandler = api.addFileToHandler, uploadData = api.uploadData, paramsStore = api.paramsStore, proxyGroupId = qq.getUniqueId();
+ qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {
+ var blobSize = record.size, id;
+ if (record.blob instanceof qq.BlobProxy) {
+ blobSize = -1;
+ }
+ id = uploadData.addFile({
+ uuid: record.uuid,
+ name: record.name,
+ size: blobSize,
+ batchId: batchId,
+ proxyGroupId: proxyGroupId
+ });
+ if (record.blob instanceof qq.BlobProxy) {
+ scaledIds.push(id);
+ } else {
+ originalId = id;
+ }
+ if (record.blob) {
+ addFileToHandler(id, record.blob);
+ fileList.push({
+ id: id,
+ file: record.blob
+ });
+ } else {
+ uploadData.setStatus(id, qq.status.REJECTED);
+ }
+ });
+ if (originalId !== null) {
+ qq.each(scaledIds, function(idx, scaledId) {
+ var params = {
+ qqparentuuid: uploadData.retrieve({
+ id: originalId
+ }).uuid,
+ qqparentsize: uploadData.retrieve({
+ id: originalId
+ }).size
+ };
+ params[uuidParamName] = uploadData.retrieve({
+ id: scaledId
+ }).uuid;
+ uploadData.setParentId(scaledId, originalId);
+ paramsStore.addReadOnly(scaledId, params);
+ });
+ if (scaledIds.length) {
+ (function() {
+ var param = {};
+ param[uuidParamName] = uploadData.retrieve({
+ id: originalId
+ }).uuid;
+ paramsStore.addReadOnly(originalId, param);
+ })();
+ }
+ }
+ }
+ });
+ };
+ qq.extend(qq.Scaler.prototype, {
+ scaleImage: function(id, specs, api) {
+ "use strict";
+ if (!qq.supportedFeatures.scaling) {
+ throw new qq.Error("Scaling is not supported in this browser!");
+ }
+ var scalingEffort = new qq.Promise(), log = api.log, file = api.getFile(id), uploadData = api.uploadData.retrieve({
+ id: id
+ }), name = uploadData && uploadData.name, uuid = uploadData && uploadData.uuid, scalingOptions = {
+ customResizer: specs.customResizer,
+ sendOriginal: false,
+ orient: specs.orient,
+ defaultType: specs.type || null,
+ defaultQuality: specs.quality,
+ failedToScaleText: "Unable to scale",
+ sizes: [ {
+ name: "",
+ maxSize: specs.maxSize
+ } ]
+ }, scaler = new qq.Scaler(scalingOptions, log);
+ if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {
+ scalingEffort.failure();
+ log("Could not generate requested scaled image for " + id + ". " + "Scaling is either not possible in this browser, or the file could not be located.", "error");
+ } else {
+ qq.bind(function() {
+ var record = scaler.getFileRecords(uuid, name, file)[0];
+ if (record && record.blob instanceof qq.BlobProxy) {
+ record.blob.create().then(scalingEffort.success, scalingEffort.failure);
+ } else {
+ log(id + " is not a scalable image!", "error");
+ scalingEffort.failure();
+ }
+ }, this)();
+ }
+ return scalingEffort;
+ },
+ _determineOutputType: function(spec) {
+ "use strict";
+ var requestedType = spec.requestedType, defaultType = spec.defaultType, referenceType = spec.refType;
+ if (!defaultType && !requestedType) {
+ if (referenceType !== "image/jpeg") {
+ return "image/png";
+ }
+ return referenceType;
+ }
+ if (!requestedType) {
+ return defaultType;
+ }
+ if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {
+ if (requestedType === "image/tiff") {
+ return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;
+ }
+ return requestedType;
+ }
+ return defaultType;
+ },
+ _getName: function(originalName, scaledVersionProperties) {
+ "use strict";
+ var startOfExt = originalName.lastIndexOf("."), versionType = scaledVersionProperties.type || "image/png", referenceType = scaledVersionProperties.refType, scaledName = "", scaledExt = qq.getExtension(originalName), nameAppendage = "";
+ if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {
+ nameAppendage = " (" + scaledVersionProperties.name + ")";
+ }
+ if (startOfExt >= 0) {
+ scaledName = originalName.substr(0, startOfExt);
+ if (referenceType !== versionType) {
+ scaledExt = versionType.split("/")[1];
+ }
+ scaledName += nameAppendage + "." + scaledExt;
+ } else {
+ scaledName = originalName + nameAppendage;
+ }
+ return scaledName;
+ },
+ _getSortedSizes: function(sizes) {
+ "use strict";
+ sizes = qq.extend([], sizes);
+ return sizes.sort(function(a, b) {
+ if (a.maxSize > b.maxSize) {
+ return 1;
+ }
+ if (a.maxSize < b.maxSize) {
+ return -1;
+ }
+ return 0;
+ });
+ },
+ _generateScaledImage: function(spec, sourceFile) {
+ "use strict";
+ var self = this, customResizeFunction = spec.customResizeFunction, log = spec.log, maxSize = spec.maxSize, orient = spec.orient, type = spec.type, quality = spec.quality, failedText = spec.failedText, includeExif = spec.includeExif && sourceFile.type === "image/jpeg" && type === "image/jpeg", scalingEffort = new qq.Promise(), imageGenerator = new qq.ImageGenerator(log), canvas = document.createElement("canvas");
+ log("Attempting to generate scaled version for " + sourceFile.name);
+ imageGenerator.generate(sourceFile, canvas, {
+ maxSize: maxSize,
+ orient: orient,
+ customResizeFunction: customResizeFunction
+ }).then(function() {
+ var scaledImageDataUri = canvas.toDataURL(type, quality), signalSuccess = function() {
+ log("Success generating scaled version for " + sourceFile.name);
+ var blob = qq.dataUriToBlob(scaledImageDataUri);
+ scalingEffort.success(blob);
+ };
+ if (includeExif) {
+ self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {
+ scaledImageDataUri = scaledImageDataUriWithExif;
+ signalSuccess();
+ }, function() {
+ log("Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.", "error");
+ signalSuccess();
+ });
+ } else {
+ signalSuccess();
+ }
+ }, function() {
+ log("Failed attempt to generate scaled version for " + sourceFile.name, "error");
+ scalingEffort.failure(failedText);
+ });
+ return scalingEffort;
+ },
+ _insertExifHeader: function(originalImage, scaledImageDataUri, log) {
+ "use strict";
+ var reader = new FileReader(), insertionEffort = new qq.Promise(), originalImageDataUri = "";
+ reader.onload = function() {
+ originalImageDataUri = reader.result;
+ insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));
+ };
+ reader.onerror = function() {
+ log("Problem reading " + originalImage.name + " during attempt to transfer EXIF data to scaled version.", "error");
+ insertionEffort.failure();
+ };
+ reader.readAsDataURL(originalImage);
+ return insertionEffort;
+ },
+ _dataUriToBlob: function(dataUri) {
+ "use strict";
+ var byteString, mimeString, arrayBuffer, intArray;
+ if (dataUri.split(",")[0].indexOf("base64") >= 0) {
+ byteString = atob(dataUri.split(",")[1]);
+ } else {
+ byteString = decodeURI(dataUri.split(",")[1]);
+ }
+ mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0];
+ arrayBuffer = new ArrayBuffer(byteString.length);
+ intArray = new Uint8Array(arrayBuffer);
+ qq.each(byteString, function(idx, character) {
+ intArray[idx] = character.charCodeAt(0);
+ });
+ return this._createBlob(arrayBuffer, mimeString);
+ },
+ _createBlob: function(data, mime) {
+ "use strict";
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder();
+ if (blobBuilder) {
+ blobBuilder.append(data);
+ return blobBuilder.getBlob(mime);
+ } else {
+ return new Blob([ data ], {
+ type: mime
+ });
+ }
+ }
+ });
+ qq.ExifRestorer = function() {
+ var ExifRestorer = {};
+ ExifRestorer.KEY_STR = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + "ghijklmnopqrstuv" + "wxyz0123456789+/" + "=";
+ ExifRestorer.encode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0;
+ do {
+ chr1 = input[i++];
+ chr2 = input[i++];
+ chr3 = input[i++];
+ enc1 = chr1 >> 2;
+ enc2 = (chr1 & 3) << 4 | chr2 >> 4;
+ enc3 = (chr2 & 15) << 2 | chr3 >> 6;
+ enc4 = chr3 & 63;
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+ output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4);
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return output;
+ };
+ ExifRestorer.restore = function(origFileBase64, resizedFileBase64) {
+ var expectedBase64Header = "data:image/jpeg;base64,";
+ if (!origFileBase64.match(expectedBase64Header)) {
+ return resizedFileBase64;
+ }
+ var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, ""));
+ var segments = this.slice2Segments(rawImage);
+ var image = this.exifManipulation(resizedFileBase64, segments);
+ return expectedBase64Header + this.encode64(image);
+ };
+ ExifRestorer.exifManipulation = function(resizedFileBase64, segments) {
+ var exifArray = this.getExifArray(segments), newImageArray = this.insertExif(resizedFileBase64, exifArray), aBuffer = new Uint8Array(newImageArray);
+ return aBuffer;
+ };
+ ExifRestorer.getExifArray = function(segments) {
+ var seg;
+ for (var x = 0; x < segments.length; x++) {
+ seg = segments[x];
+ if (seg[0] == 255 & seg[1] == 225) {
+ return seg;
+ }
+ }
+ return [];
+ };
+ ExifRestorer.insertExif = function(resizedFileBase64, exifArray) {
+ var imageData = resizedFileBase64.replace("data:image/jpeg;base64,", ""), buf = this.decode64(imageData), separatePoint = buf.indexOf(255, 3), mae = buf.slice(0, separatePoint), ato = buf.slice(separatePoint), array = mae;
+ array = array.concat(exifArray);
+ array = array.concat(ato);
+ return array;
+ };
+ ExifRestorer.slice2Segments = function(rawImageArray) {
+ var head = 0, segments = [];
+ while (1) {
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218) {
+ break;
+ }
+ if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216) {
+ head += 2;
+ } else {
+ var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3], endPoint = head + length + 2, seg = rawImageArray.slice(head, endPoint);
+ segments.push(seg);
+ head = endPoint;
+ }
+ if (head > rawImageArray.length) {
+ break;
+ }
+ }
+ return segments;
+ };
+ ExifRestorer.decode64 = function(input) {
+ var output = "", chr1, chr2, chr3 = "", enc1, enc2, enc3, enc4 = "", i = 0, buf = [];
+ var base64test = /[^A-Za-z0-9\+\/\=]/g;
+ if (base64test.exec(input)) {
+ throw new Error("There were invalid base64 characters in the input text. " + "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='");
+ }
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+ do {
+ enc1 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc2 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc3 = this.KEY_STR.indexOf(input.charAt(i++));
+ enc4 = this.KEY_STR.indexOf(input.charAt(i++));
+ chr1 = enc1 << 2 | enc2 >> 4;
+ chr2 = (enc2 & 15) << 4 | enc3 >> 2;
+ chr3 = (enc3 & 3) << 6 | enc4;
+ buf.push(chr1);
+ if (enc3 != 64) {
+ buf.push(chr2);
+ }
+ if (enc4 != 64) {
+ buf.push(chr3);
+ }
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+ return buf;
+ };
+ return ExifRestorer;
+ }();
+ qq.TotalProgress = function(callback, getSize) {
+ "use strict";
+ var perFileProgress = {}, totalLoaded = 0, totalSize = 0, lastLoadedSent = -1, lastTotalSent = -1, callbackProxy = function(loaded, total) {
+ if (loaded !== lastLoadedSent || total !== lastTotalSent) {
+ callback(loaded, total);
+ }
+ lastLoadedSent = loaded;
+ lastTotalSent = total;
+ }, noRetryableFiles = function(failed, retryable) {
+ var none = true;
+ qq.each(failed, function(idx, failedId) {
+ if (qq.indexOf(retryable, failedId) >= 0) {
+ none = false;
+ return false;
+ }
+ });
+ return none;
+ }, onCancel = function(id) {
+ updateTotalProgress(id, -1, -1);
+ delete perFileProgress[id];
+ }, onAllComplete = function(successful, failed, retryable) {
+ if (failed.length === 0 || noRetryableFiles(failed, retryable)) {
+ callbackProxy(totalSize, totalSize);
+ this.reset();
+ }
+ }, onNew = function(id) {
+ var size = getSize(id);
+ if (size > 0) {
+ updateTotalProgress(id, 0, size);
+ perFileProgress[id] = {
+ loaded: 0,
+ total: size
+ };
+ }
+ }, updateTotalProgress = function(id, newLoaded, newTotal) {
+ var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0, oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;
+ if (newLoaded === -1 && newTotal === -1) {
+ totalLoaded -= oldLoaded;
+ totalSize -= oldTotal;
+ } else {
+ if (newLoaded) {
+ totalLoaded += newLoaded - oldLoaded;
+ }
+ if (newTotal) {
+ totalSize += newTotal - oldTotal;
+ }
+ }
+ callbackProxy(totalLoaded, totalSize);
+ };
+ qq.extend(this, {
+ onAllComplete: onAllComplete,
+ onStatusChange: function(id, oldStatus, newStatus) {
+ if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {
+ onCancel(id);
+ } else if (newStatus === qq.status.SUBMITTING) {
+ onNew(id);
+ }
+ },
+ onIndividualProgress: function(id, loaded, total) {
+ updateTotalProgress(id, loaded, total);
+ perFileProgress[id] = {
+ loaded: loaded,
+ total: total
+ };
+ },
+ onNewSize: function(id) {
+ onNew(id);
+ },
+ reset: function() {
+ perFileProgress = {};
+ totalLoaded = 0;
+ totalSize = 0;
+ }
+ });
+ };
+ qq.PasteSupport = function(o) {
+ "use strict";
+ var options, detachPasteHandler;
+ options = {
+ targetElement: null,
+ callbacks: {
+ log: function(message, level) {},
+ pasteReceived: function(blob) {}
+ }
+ };
+ function isImage(item) {
+ return item.type && item.type.indexOf("image/") === 0;
+ }
+ function registerPasteHandler() {
+ detachPasteHandler = qq(options.targetElement).attach("paste", function(event) {
+ var clipboardData = event.clipboardData;
+ if (clipboardData) {
+ qq.each(clipboardData.items, function(idx, item) {
+ if (isImage(item)) {
+ var blob = item.getAsFile();
+ options.callbacks.pasteReceived(blob);
+ }
+ });
+ }
+ });
+ }
+ function unregisterPasteHandler() {
+ if (detachPasteHandler) {
+ detachPasteHandler();
+ }
+ }
+ qq.extend(options, o);
+ registerPasteHandler();
+ qq.extend(this, {
+ reset: function() {
+ unregisterPasteHandler();
+ }
+ });
+ };
+ qq.FormSupport = function(options, startUpload, log) {
+ "use strict";
+ var self = this, interceptSubmit = options.interceptSubmit, formEl = options.element, autoUpload = options.autoUpload;
+ qq.extend(this, {
+ newEndpoint: null,
+ newAutoUpload: autoUpload,
+ attachedToForm: false,
+ getFormInputsAsObject: function() {
+ if (formEl == null) {
+ return null;
+ }
+ return self._form2Obj(formEl);
+ }
+ });
+ function determineNewEndpoint(formEl) {
+ if (formEl.getAttribute("action")) {
+ self.newEndpoint = formEl.getAttribute("action");
+ }
+ }
+ function validateForm(formEl, nativeSubmit) {
+ if (formEl.checkValidity && !formEl.checkValidity()) {
+ log("Form did not pass validation checks - will not upload.", "error");
+ nativeSubmit();
+ } else {
+ return true;
+ }
+ }
+ function maybeUploadOnSubmit(formEl) {
+ var nativeSubmit = formEl.submit;
+ qq(formEl).attach("submit", function(event) {
+ event = event || window.event;
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
+ validateForm(formEl, nativeSubmit) && startUpload();
+ });
+ formEl.submit = function() {
+ validateForm(formEl, nativeSubmit) && startUpload();
+ };
+ }
+ function determineFormEl(formEl) {
+ if (formEl) {
+ if (qq.isString(formEl)) {
+ formEl = document.getElementById(formEl);
+ }
+ if (formEl) {
+ log("Attaching to form element.");
+ determineNewEndpoint(formEl);
+ interceptSubmit && maybeUploadOnSubmit(formEl);
+ }
+ }
+ return formEl;
+ }
+ formEl = determineFormEl(formEl);
+ this.attachedToForm = !!formEl;
+ };
+ qq.extend(qq.FormSupport.prototype, {
+ _form2Obj: function(form) {
+ "use strict";
+ var obj = {}, notIrrelevantType = function(type) {
+ var irrelevantTypes = [ "button", "image", "reset", "submit" ];
+ return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;
+ }, radioOrCheckbox = function(type) {
+ return qq.indexOf([ "checkbox", "radio" ], type.toLowerCase()) >= 0;
+ }, ignoreValue = function(el) {
+ if (radioOrCheckbox(el.type) && !el.checked) {
+ return true;
+ }
+ return el.disabled && el.type.toLowerCase() !== "hidden";
+ }, selectValue = function(select) {
+ var value = null;
+ qq.each(qq(select).children(), function(idx, child) {
+ if (child.tagName.toLowerCase() === "option" && child.selected) {
+ value = child.value;
+ return false;
+ }
+ });
+ return value;
+ };
+ qq.each(form.elements, function(idx, el) {
+ if ((qq.isInput(el, true) || el.tagName.toLowerCase() === "textarea") && notIrrelevantType(el.type) && !ignoreValue(el)) {
+ obj[el.name] = el.value;
+ } else if (el.tagName.toLowerCase() === "select" && !ignoreValue(el)) {
+ var value = selectValue(el);
+ if (value !== null) {
+ obj[el.name] = value;
+ }
+ }
+ });
+ return obj;
+ }
+ });
+ qq.traditional = qq.traditional || {};
+ qq.traditional.FormUploadHandler = function(options, proxy) {
+ "use strict";
+ var handler = this, getName = proxy.getName, getUuid = proxy.getUuid, log = proxy.log;
+ function getIframeContentJson(id, iframe) {
+ var response, doc, innerHtml;
+ try {
+ doc = iframe.contentDocument || iframe.contentWindow.document;
+ innerHtml = doc.body.innerHTML;
+ log("converting iframe's innerHTML to JSON");
+ log("innerHTML = " + innerHtml);
+ if (innerHtml && innerHtml.match(/^ 1 && !options.allowMultipleItems) {
+ options.callbacks.processingDroppedFilesComplete([]);
+ options.callbacks.dropError("tooManyFilesError", "");
+ uploadDropZone.dropDisabled(false);
+ handleDataTransferPromise.failure();
+ } else {
+ droppedFiles = [];
+ if (qq.isFolderDropSupported(dataTransfer)) {
+ qq.each(dataTransfer.items, function(idx, item) {
+ var entry = item.webkitGetAsEntry();
+ if (entry) {
+ if (entry.isFile) {
+ droppedFiles.push(item.getAsFile());
+ } else {
+ pendingFolderPromises.push(traverseFileTree(entry).done(function() {
+ pendingFolderPromises.pop();
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }));
+ }
+ }
+ });
+ } else {
+ droppedFiles = dataTransfer.files;
+ }
+ if (pendingFolderPromises.length === 0) {
+ handleDataTransferPromise.success();
+ }
+ }
+ return handleDataTransferPromise;
+ }
+ function setupDropzone(dropArea) {
+ var dropZone = new qq.UploadDropZone({
+ HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,
+ element: dropArea,
+ onEnter: function(e) {
+ qq(dropArea).addClass(options.classes.dropActive);
+ e.stopPropagation();
+ },
+ onLeaveNotDescendants: function(e) {
+ qq(dropArea).removeClass(options.classes.dropActive);
+ },
+ onDrop: function(e) {
+ handleDataTransfer(e.dataTransfer, dropZone).then(function() {
+ uploadDroppedFiles(droppedFiles, dropZone);
+ }, function() {
+ options.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.", "error");
+ });
+ }
+ });
+ disposeSupport.addDisposer(function() {
+ dropZone.dispose();
+ });
+ qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();
+ uploadDropZones.push(dropZone);
+ return dropZone;
+ }
+ function isFileDrag(dragEvent) {
+ var fileDrag;
+ qq.each(dragEvent.dataTransfer.types, function(key, val) {
+ if (val === "Files") {
+ fileDrag = true;
+ return false;
+ }
+ });
+ return fileDrag;
+ }
+ function leavingDocumentOut(e) {
+ if (qq.firefox()) {
+ return !e.relatedTarget;
+ }
+ if (qq.safari()) {
+ return e.x < 0 || e.y < 0;
+ }
+ return e.x === 0 && e.y === 0;
+ }
+ function setupDragDrop() {
+ var dropZones = options.dropZoneElements, maybeHideDropZones = function() {
+ setTimeout(function() {
+ qq.each(dropZones, function(idx, dropZone) {
+ qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();
+ qq(dropZone).removeClass(options.classes.dropActive);
+ });
+ }, 10);
+ };
+ qq.each(dropZones, function(idx, dropZone) {
+ var uploadDropZone = setupDropzone(dropZone);
+ if (dropZones.length && qq.supportedFeatures.fileDrop) {
+ disposeSupport.attach(document, "dragenter", function(e) {
+ if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {
+ qq.each(dropZones, function(idx, dropZone) {
+ if (dropZone instanceof HTMLElement && qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {
+ qq(dropZone).css({
+ display: "block"
+ });
+ }
+ });
+ }
+ });
+ }
+ });
+ disposeSupport.attach(document, "dragleave", function(e) {
+ if (leavingDocumentOut(e)) {
+ maybeHideDropZones();
+ }
+ });
+ disposeSupport.attach(qq(document).children()[0], "mouseenter", function(e) {
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, "drop", function(e) {
+ e.preventDefault();
+ maybeHideDropZones();
+ });
+ disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);
+ }
+ setupDragDrop();
+ qq.extend(this, {
+ setupExtraDropzone: function(element) {
+ options.dropZoneElements.push(element);
+ setupDropzone(element);
+ },
+ removeDropzone: function(element) {
+ var i, dzs = options.dropZoneElements;
+ for (i in dzs) {
+ if (dzs[i] === element) {
+ return dzs.splice(i, 1);
+ }
+ }
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ qq.each(uploadDropZones, function(idx, dropZone) {
+ dropZone.dispose();
+ });
+ }
+ });
+ };
+ qq.DragAndDrop.callbacks = function() {
+ "use strict";
+ return {
+ processingDroppedFiles: function() {},
+ processingDroppedFilesComplete: function(files, targetEl) {},
+ dropError: function(code, errorSpecifics) {
+ qq.log("Drag & drop error code '" + code + " with these specifics: '" + errorSpecifics + "'", "error");
+ },
+ dropLog: function(message, level) {
+ qq.log(message, level);
+ }
+ };
+ };
+ qq.UploadDropZone = function(o) {
+ "use strict";
+ var disposeSupport = new qq.DisposeSupport(), options, element, preventDrop, dropOutsideDisabled;
+ options = {
+ element: null,
+ onEnter: function(e) {},
+ onLeave: function(e) {},
+ onLeaveNotDescendants: function(e) {},
+ onDrop: function(e) {}
+ };
+ qq.extend(options, o);
+ element = options.element;
+ function dragoverShouldBeCanceled() {
+ return qq.safari() || qq.firefox() && qq.windows();
+ }
+ function disableDropOutside(e) {
+ if (!dropOutsideDisabled) {
+ if (dragoverShouldBeCanceled) {
+ disposeSupport.attach(document, "dragover", function(e) {
+ e.preventDefault();
+ });
+ } else {
+ disposeSupport.attach(document, "dragover", function(e) {
+ if (e.dataTransfer) {
+ e.dataTransfer.dropEffect = "none";
+ e.preventDefault();
+ }
+ });
+ }
+ dropOutsideDisabled = true;
+ }
+ }
+ function isValidFileDrag(e) {
+ if (!qq.supportedFeatures.fileDrop) {
+ return false;
+ }
+ var effectTest, dt = e.dataTransfer, isSafari = qq.safari();
+ effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== "none";
+ return dt && effectTest && (dt.files || !isSafari && dt.types.contains && dt.types.contains("Files"));
+ }
+ function isOrSetDropDisabled(isDisabled) {
+ if (isDisabled !== undefined) {
+ preventDrop = isDisabled;
+ }
+ return preventDrop;
+ }
+ function triggerHidezonesEvent() {
+ var hideZonesEvent;
+ function triggerUsingOldApi() {
+ hideZonesEvent = document.createEvent("Event");
+ hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);
+ }
+ if (window.CustomEvent) {
+ try {
+ hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);
+ } catch (err) {
+ triggerUsingOldApi();
+ }
+ } else {
+ triggerUsingOldApi();
+ }
+ document.dispatchEvent(hideZonesEvent);
+ }
+ function attachEvents() {
+ disposeSupport.attach(element, "dragover", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;
+ if (effect === "move" || effect === "linkMove") {
+ e.dataTransfer.dropEffect = "move";
+ } else {
+ e.dataTransfer.dropEffect = "copy";
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ disposeSupport.attach(element, "dragenter", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onEnter(e);
+ }
+ });
+ disposeSupport.attach(element, "dragleave", function(e) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ options.onLeave(e);
+ var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
+ if (qq(this).contains(relatedTarget)) {
+ return;
+ }
+ options.onLeaveNotDescendants(e);
+ });
+ disposeSupport.attach(element, "drop", function(e) {
+ if (!isOrSetDropDisabled()) {
+ if (!isValidFileDrag(e)) {
+ return;
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ options.onDrop(e);
+ triggerHidezonesEvent();
+ }
+ });
+ }
+ disableDropOutside();
+ attachEvents();
+ qq.extend(this, {
+ dropDisabled: function(isDisabled) {
+ return isOrSetDropDisabled(isDisabled);
+ },
+ dispose: function() {
+ disposeSupport.dispose();
+ },
+ getElement: function() {
+ return element;
+ }
+ });
+ };
+ (function() {
+ "use strict";
+ qq.uiPublicApi = {
+ addInitialFiles: function(cannedFileList) {
+ this._parent.prototype.addInitialFiles.apply(this, arguments);
+ this._templating.addCacheToDom();
+ },
+ clearStoredFiles: function() {
+ this._parent.prototype.clearStoredFiles.apply(this, arguments);
+ this._templating.clearFiles();
+ },
+ addExtraDropzone: function(element) {
+ this._dnd && this._dnd.setupExtraDropzone(element);
+ },
+ removeExtraDropzone: function(element) {
+ if (this._dnd) {
+ return this._dnd.removeDropzone(element);
+ }
+ },
+ getItemByFileId: function(id) {
+ if (!this._templating.isHiddenForever(id)) {
+ return this._templating.getFileContainer(id);
+ }
+ },
+ reset: function() {
+ this._parent.prototype.reset.apply(this, arguments);
+ this._templating.reset();
+ if (!this._options.button && this._templating.getButton()) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._templating.getButton(),
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ if (this._dnd) {
+ this._dnd.dispose();
+ this._dnd = this._setupDragAndDrop();
+ }
+ this._totalFilesInBatch = 0;
+ this._filesInBatchAddedToUi = 0;
+ this._setupClickAndEditEventHandlers();
+ },
+ setName: function(id, newName) {
+ var formattedFilename = this._options.formatFileName(newName);
+ this._parent.prototype.setName.apply(this, arguments);
+ this._templating.updateFilename(id, formattedFilename);
+ },
+ pauseUpload: function(id) {
+ var paused = this._parent.prototype.pauseUpload.apply(this, arguments);
+ paused && this._templating.uploadPaused(id);
+ return paused;
+ },
+ continueUpload: function(id) {
+ var continued = this._parent.prototype.continueUpload.apply(this, arguments);
+ continued && this._templating.uploadContinued(id);
+ return continued;
+ },
+ getId: function(fileContainerOrChildEl) {
+ return this._templating.getFileId(fileContainerOrChildEl);
+ },
+ getDropTarget: function(fileId) {
+ var file = this.getFile(fileId);
+ return file.qqDropTarget;
+ }
+ };
+ qq.uiPrivateApi = {
+ _getButton: function(buttonId) {
+ var button = this._parent.prototype._getButton.apply(this, arguments);
+ if (!button) {
+ if (buttonId === this._defaultButtonId) {
+ button = this._templating.getButton();
+ }
+ }
+ return button;
+ },
+ _removeFileItem: function(fileId) {
+ this._templating.removeFile(fileId);
+ },
+ _setupClickAndEditEventHandlers: function() {
+ this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();
+ this._focusinEventSupported = !qq.firefox();
+ if (this._isEditFilenameEnabled()) {
+ this._filenameClickHandler = this._bindFilenameClickEvent();
+ this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();
+ this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();
+ }
+ },
+ _setupDragAndDrop: function() {
+ var self = this, dropZoneElements = this._options.dragAndDrop.extraDropzones, templating = this._templating, defaultDropZone = templating.getDropZone();
+ defaultDropZone && dropZoneElements.push(defaultDropZone);
+ return new qq.DragAndDrop({
+ dropZoneElements: dropZoneElements,
+ allowMultipleItems: this._options.multiple,
+ classes: {
+ dropActive: this._options.classes.dropActive
+ },
+ callbacks: {
+ processingDroppedFiles: function() {
+ templating.showDropProcessing();
+ },
+ processingDroppedFilesComplete: function(files, targetEl) {
+ templating.hideDropProcessing();
+ qq.each(files, function(idx, file) {
+ file.qqDropTarget = targetEl;
+ });
+ if (files.length) {
+ self.addFiles(files, null, null);
+ }
+ },
+ dropError: function(code, errorData) {
+ self._itemError(code, errorData);
+ },
+ dropLog: function(message, level) {
+ self.log(message, level);
+ }
+ }
+ });
+ },
+ _bindFileButtonsClickEvent: function() {
+ var self = this;
+ return new qq.FileButtonsClickHandler({
+ templating: this._templating,
+ log: function(message, lvl) {
+ self.log(message, lvl);
+ },
+ onDeleteFile: function(fileId) {
+ self.deleteFile(fileId);
+ },
+ onCancel: function(fileId) {
+ self.cancel(fileId);
+ },
+ onRetry: function(fileId) {
+ self.retry(fileId);
+ },
+ onPause: function(fileId) {
+ self.pauseUpload(fileId);
+ },
+ onContinue: function(fileId) {
+ self.continueUpload(fileId);
+ },
+ onGetName: function(fileId) {
+ return self.getName(fileId);
+ }
+ });
+ },
+ _isEditFilenameEnabled: function() {
+ return this._templating.isEditFilenamePossible() && !this._options.autoUpload && qq.FilenameClickHandler && qq.FilenameInputFocusHandler && qq.FilenameInputFocusHandler;
+ },
+ _filenameEditHandler: function() {
+ var self = this, templating = this._templating;
+ return {
+ templating: templating,
+ log: function(message, lvl) {
+ self.log(message, lvl);
+ },
+ onGetUploadStatus: function(fileId) {
+ return self.getUploads({
+ id: fileId
+ }).status;
+ },
+ onGetName: function(fileId) {
+ return self.getName(fileId);
+ },
+ onSetName: function(id, newName) {
+ self.setName(id, newName);
+ },
+ onEditingStatusChange: function(id, isEditing) {
+ var qqInput = qq(templating.getEditInput(id)), qqFileContainer = qq(templating.getFileContainer(id));
+ if (isEditing) {
+ qqInput.addClass("qq-editing");
+ templating.hideFilename(id);
+ templating.hideEditIcon(id);
+ } else {
+ qqInput.removeClass("qq-editing");
+ templating.showFilename(id);
+ templating.showEditIcon(id);
+ }
+ qqFileContainer.addClass("qq-temp").removeClass("qq-temp");
+ }
+ };
+ },
+ _onUploadStatusChange: function(id, oldStatus, newStatus) {
+ this._parent.prototype._onUploadStatusChange.apply(this, arguments);
+ if (this._isEditFilenameEnabled()) {
+ if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {
+ this._templating.markFilenameEditable(id);
+ this._templating.hideEditIcon(id);
+ }
+ }
+ if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {
+ this._templating.hideRetry(id);
+ this._templating.setStatusText(id);
+ qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);
+ } else if (newStatus === qq.status.UPLOAD_FAILED) {
+ this._templating.hidePause(id);
+ }
+ },
+ _bindFilenameInputFocusInEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameInputFocusInHandler(spec);
+ },
+ _bindFilenameInputFocusEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameInputFocusHandler(spec);
+ },
+ _bindFilenameClickEvent: function() {
+ var spec = qq.extend({}, this._filenameEditHandler());
+ return new qq.FilenameClickHandler(spec);
+ },
+ _storeForLater: function(id) {
+ this._parent.prototype._storeForLater.apply(this, arguments);
+ this._templating.hideSpinner(id);
+ },
+ _onAllComplete: function(successful, failed) {
+ this._parent.prototype._onAllComplete.apply(this, arguments);
+ this._templating.resetTotalProgress();
+ },
+ _onSubmit: function(id, name) {
+ var file = this.getFile(id);
+ if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {
+ this._paramsStore.addReadOnly(id, {
+ qqpath: file.qqPath
+ });
+ }
+ this._parent.prototype._onSubmit.apply(this, arguments);
+ this._addToList(id, name);
+ },
+ _onSubmitted: function(id) {
+ if (this._isEditFilenameEnabled()) {
+ this._templating.markFilenameEditable(id);
+ this._templating.showEditIcon(id);
+ if (!this._focusinEventSupported) {
+ this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));
+ }
+ }
+ },
+ _onProgress: function(id, name, loaded, total) {
+ this._parent.prototype._onProgress.apply(this, arguments);
+ this._templating.updateProgress(id, loaded, total);
+ if (total === 0 || Math.round(loaded / total * 100) === 100) {
+ this._templating.hideCancel(id);
+ this._templating.hidePause(id);
+ this._templating.hideProgress(id);
+ this._templating.setStatusText(id, this._options.text.waitingForResponse);
+ this._displayFileSize(id);
+ } else {
+ this._displayFileSize(id, loaded, total);
+ }
+ },
+ _onTotalProgress: function(loaded, total) {
+ this._parent.prototype._onTotalProgress.apply(this, arguments);
+ this._templating.updateTotalProgress(loaded, total);
+ },
+ _onComplete: function(id, name, result, xhr) {
+ var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments), templating = this._templating, fileContainer = templating.getFileContainer(id), self = this;
+ function completeUpload(result) {
+ if (!fileContainer) {
+ return;
+ }
+ templating.setStatusText(id);
+ qq(fileContainer).removeClass(self._classes.retrying);
+ templating.hideProgress(id);
+ if (self.getUploads({
+ id: id
+ }).status !== qq.status.UPLOAD_FAILED) {
+ templating.hideCancel(id);
+ }
+ templating.hideSpinner(id);
+ if (result.success) {
+ self._markFileAsSuccessful(id);
+ } else {
+ qq(fileContainer).addClass(self._classes.fail);
+ templating.showCancel(id);
+ if (templating.isRetryPossible() && !self._preventRetries[id]) {
+ qq(fileContainer).addClass(self._classes.retryable);
+ templating.showRetry(id);
+ }
+ self._controlFailureTextDisplay(id, result);
+ }
+ }
+ if (parentRetVal instanceof qq.Promise) {
+ parentRetVal.done(function(newResult) {
+ completeUpload(newResult);
+ });
+ } else {
+ completeUpload(result);
+ }
+ return parentRetVal;
+ },
+ _markFileAsSuccessful: function(id) {
+ var templating = this._templating;
+ if (this._isDeletePossible()) {
+ templating.showDeleteButton(id);
+ }
+ qq(templating.getFileContainer(id)).addClass(this._classes.success);
+ this._maybeUpdateThumbnail(id);
+ },
+ _onUploadPrep: function(id) {
+ this._parent.prototype._onUploadPrep.apply(this, arguments);
+ this._templating.showSpinner(id);
+ },
+ _onUpload: function(id, name) {
+ var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);
+ this._templating.showSpinner(id);
+ return parentRetVal;
+ },
+ _onUploadChunk: function(id, chunkData) {
+ this._parent.prototype._onUploadChunk.apply(this, arguments);
+ if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {
+ this._templating.allowPause(id);
+ }
+ },
+ _onCancel: function(id, name) {
+ this._parent.prototype._onCancel.apply(this, arguments);
+ this._removeFileItem(id);
+ if (this._getNotFinished() === 0) {
+ this._templating.resetTotalProgress();
+ }
+ },
+ _onBeforeAutoRetry: function(id) {
+ var retryNumForDisplay, maxAuto, retryNote;
+ this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);
+ this._showCancelLink(id);
+ if (this._options.retry.showAutoRetryNote) {
+ retryNumForDisplay = this._autoRetries[id];
+ maxAuto = this._options.retry.maxAutoAttempts;
+ retryNote = this._options.retry.autoRetryNote.replace(/\{retryNum\}/g, retryNumForDisplay);
+ retryNote = retryNote.replace(/\{maxAuto\}/g, maxAuto);
+ this._templating.setStatusText(id, retryNote);
+ qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);
+ }
+ },
+ _onBeforeManualRetry: function(id) {
+ if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {
+ this._templating.resetProgress(id);
+ qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);
+ this._templating.setStatusText(id);
+ this._templating.showSpinner(id);
+ this._showCancelLink(id);
+ return true;
+ } else {
+ qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);
+ this._templating.showRetry(id);
+ return false;
+ }
+ },
+ _onSubmitDelete: function(id) {
+ var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);
+ this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);
+ },
+ _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {
+ if (this._options.deleteFile.forceConfirm) {
+ this._showDeleteConfirm.apply(this, arguments);
+ } else {
+ this._sendDeleteRequest.apply(this, arguments);
+ }
+ },
+ _onDeleteComplete: function(id, xhr, isError) {
+ this._parent.prototype._onDeleteComplete.apply(this, arguments);
+ this._templating.hideSpinner(id);
+ if (isError) {
+ this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);
+ this._templating.showDeleteButton(id);
+ } else {
+ this._removeFileItem(id);
+ }
+ },
+ _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {
+ this._templating.hideDeleteButton(id);
+ this._templating.showSpinner(id);
+ this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);
+ this._deleteHandler.sendDelete.apply(this, arguments);
+ },
+ _showDeleteConfirm: function(id, uuid, mandatedParams) {
+ var fileName = this.getName(id), confirmMessage = this._options.deleteFile.confirmMessage.replace(/\{filename\}/g, fileName), uuid = this.getUuid(id), deleteRequestArgs = arguments, self = this, retVal;
+ retVal = this._options.showConfirm(confirmMessage);
+ if (qq.isGenericPromise(retVal)) {
+ retVal.then(function() {
+ self._sendDeleteRequest.apply(self, deleteRequestArgs);
+ });
+ } else if (retVal !== false) {
+ self._sendDeleteRequest.apply(self, deleteRequestArgs);
+ }
+ },
+ _addToList: function(id, name, canned) {
+ var prependData, prependIndex = 0, dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled, record;
+ if (this._options.display.prependFiles) {
+ if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {
+ prependIndex = this._filesInBatchAddedToUi - 1;
+ }
+ prependData = {
+ index: prependIndex
+ };
+ }
+ if (!canned) {
+ if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {
+ this._templating.disableCancel();
+ }
+ if (!this._options.multiple) {
+ record = this.getUploads({
+ id: id
+ });
+ this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;
+ if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {
+ this._handler.cancelAll();
+ this._clearList();
+ this._handledProxyGroup = null;
+ }
+ }
+ }
+ if (canned) {
+ this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);
+ this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);
+ } else {
+ this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);
+ this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);
+ }
+ this._filesInBatchAddedToUi += 1;
+ if (canned || this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading) {
+ this._displayFileSize(id);
+ }
+ },
+ _clearList: function() {
+ this._templating.clearFiles();
+ this.clearStoredFiles();
+ },
+ _displayFileSize: function(id, loadedSize, totalSize) {
+ var size = this.getSize(id), sizeForDisplay = this._formatSize(size);
+ if (size >= 0) {
+ if (loadedSize !== undefined && totalSize !== undefined) {
+ sizeForDisplay = this._formatProgress(loadedSize, totalSize);
+ }
+ this._templating.updateSize(id, sizeForDisplay);
+ }
+ },
+ _formatProgress: function(uploadedSize, totalSize) {
+ var message = this._options.text.formatProgress;
+ function r(name, replacement) {
+ message = message.replace(name, replacement);
+ }
+ r("{percent}", Math.round(uploadedSize / totalSize * 100));
+ r("{total_size}", this._formatSize(totalSize));
+ return message;
+ },
+ _controlFailureTextDisplay: function(id, response) {
+ var mode, responseProperty, failureReason;
+ mode = this._options.failedUploadTextDisplay.mode;
+ responseProperty = this._options.failedUploadTextDisplay.responseProperty;
+ if (mode === "custom") {
+ failureReason = response[responseProperty];
+ if (!failureReason) {
+ failureReason = this._options.text.failUpload;
+ }
+ this._templating.setStatusText(id, failureReason);
+ if (this._options.failedUploadTextDisplay.enableTooltip) {
+ this._showTooltip(id, failureReason);
+ }
+ } else if (mode === "default") {
+ this._templating.setStatusText(id, this._options.text.failUpload);
+ } else if (mode !== "none") {
+ this.log("failedUploadTextDisplay.mode value of '" + mode + "' is not valid", "warn");
+ }
+ },
+ _showTooltip: function(id, text) {
+ this._templating.getFileContainer(id).title = text;
+ },
+ _showCancelLink: function(id) {
+ if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {
+ this._templating.showCancel(id);
+ }
+ },
+ _itemError: function(code, name, item) {
+ var message = this._parent.prototype._itemError.apply(this, arguments);
+ this._options.showMessage(message);
+ },
+ _batchError: function(message) {
+ this._parent.prototype._batchError.apply(this, arguments);
+ this._options.showMessage(message);
+ },
+ _setupPastePrompt: function() {
+ var self = this;
+ this._options.callbacks.onPasteReceived = function() {
+ var message = self._options.paste.namePromptMessage, defaultVal = self._options.paste.defaultName;
+ return self._options.showPrompt(message, defaultVal);
+ };
+ },
+ _fileOrBlobRejected: function(id, name) {
+ this._totalFilesInBatch -= 1;
+ this._parent.prototype._fileOrBlobRejected.apply(this, arguments);
+ },
+ _prepareItemsForUpload: function(items, params, endpoint) {
+ this._totalFilesInBatch = items.length;
+ this._filesInBatchAddedToUi = 0;
+ this._parent.prototype._prepareItemsForUpload.apply(this, arguments);
+ },
+ _maybeUpdateThumbnail: function(fileId) {
+ var thumbnailUrl = this._thumbnailUrls[fileId], fileStatus = this.getUploads({
+ id: fileId
+ }).status;
+ if (fileStatus !== qq.status.DELETED && (thumbnailUrl || this._options.thumbnails.placeholders.waitUntilResponse || !qq.supportedFeatures.imagePreviews)) {
+ this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);
+ }
+ },
+ _addCannedFile: function(sessionData) {
+ var id = this._parent.prototype._addCannedFile.apply(this, arguments);
+ this._addToList(id, this.getName(id), true);
+ this._templating.hideSpinner(id);
+ this._templating.hideCancel(id);
+ this._markFileAsSuccessful(id);
+ return id;
+ },
+ _setSize: function(id, newSize) {
+ this._parent.prototype._setSize.apply(this, arguments);
+ this._templating.updateSize(id, this._formatSize(newSize));
+ },
+ _sessionRequestComplete: function() {
+ this._templating.addCacheToDom();
+ this._parent.prototype._sessionRequestComplete.apply(this, arguments);
+ }
+ };
+ })();
+ qq.FineUploader = function(o, namespace) {
+ "use strict";
+ var self = this;
+ this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;
+ this._parent.apply(this, arguments);
+ qq.extend(this._options, {
+ element: null,
+ button: null,
+ listElement: null,
+ dragAndDrop: {
+ extraDropzones: [],
+ reportDirectoryPaths: false
+ },
+ text: {
+ formatProgress: "{percent}% of {total_size}",
+ failUpload: "Upload failed",
+ waitingForResponse: "Processing...",
+ paused: "Paused"
+ },
+ template: "qq-template",
+ classes: {
+ retrying: "qq-upload-retrying",
+ retryable: "qq-upload-retryable",
+ success: "qq-upload-success",
+ fail: "qq-upload-fail",
+ editable: "qq-editable",
+ hide: "qq-hide",
+ dropActive: "qq-upload-drop-area-active"
+ },
+ failedUploadTextDisplay: {
+ mode: "default",
+ responseProperty: "error",
+ enableTooltip: true
+ },
+ messages: {
+ tooManyFilesError: "You may only drop one file",
+ unsupportedBrowser: "Unrecoverable error - this browser does not permit file uploading of any kind."
+ },
+ retry: {
+ showAutoRetryNote: true,
+ autoRetryNote: "Retrying {retryNum}/{maxAuto}..."
+ },
+ deleteFile: {
+ forceConfirm: false,
+ confirmMessage: "Are you sure you want to delete {filename}?",
+ deletingStatusText: "Deleting...",
+ deletingFailedText: "Delete failed"
+ },
+ display: {
+ fileSizeOnSubmit: false,
+ prependFiles: false
+ },
+ paste: {
+ promptForName: false,
+ namePromptMessage: "Please name this image"
+ },
+ thumbnails: {
+ customResizer: null,
+ maxCount: 0,
+ placeholders: {
+ waitUntilResponse: false,
+ notAvailablePath: null,
+ waitingPath: null
+ },
+ timeBetweenThumbs: 750
+ },
+ scaling: {
+ hideScaled: false
+ },
+ showMessage: function(message) {
+ if (self._templating.hasDialog("alert")) {
+ return self._templating.showDialog("alert", message);
+ } else {
+ setTimeout(function() {
+ window.alert(message);
+ }, 0);
+ }
+ },
+ showConfirm: function(message) {
+ if (self._templating.hasDialog("confirm")) {
+ return self._templating.showDialog("confirm", message);
+ } else {
+ return window.confirm(message);
+ }
+ },
+ showPrompt: function(message, defaultValue) {
+ if (self._templating.hasDialog("prompt")) {
+ return self._templating.showDialog("prompt", message, defaultValue);
+ } else {
+ return window.prompt(message, defaultValue);
+ }
+ }
+ }, true);
+ qq.extend(this._options, o, true);
+ this._templating = new qq.Templating({
+ log: qq.bind(this.log, this),
+ templateIdOrEl: this._options.template,
+ containerEl: this._options.element,
+ fileContainerEl: this._options.listElement,
+ button: this._options.button,
+ imageGenerator: this._imageGenerator,
+ classes: {
+ hide: this._options.classes.hide,
+ editable: this._options.classes.editable
+ },
+ limits: {
+ maxThumbs: this._options.thumbnails.maxCount,
+ timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs
+ },
+ placeholders: {
+ waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,
+ thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,
+ waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath
+ },
+ text: this._options.text
+ });
+ if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {
+ this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);
+ } else if (!qq.supportedFeatures.uploading || this._options.cors.expected && !qq.supportedFeatures.uploadCors) {
+ this._templating.renderFailure(this._options.messages.unsupportedBrowser);
+ } else {
+ this._wrapCallbacks();
+ this._templating.render();
+ this._classes = this._options.classes;
+ if (!this._options.button && this._templating.getButton()) {
+ this._defaultButtonId = this._createUploadButton({
+ element: this._templating.getButton(),
+ title: this._options.text.fileInputTitle
+ }).getButtonId();
+ }
+ this._setupClickAndEditEventHandlers();
+ if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {
+ this._dnd = this._setupDragAndDrop();
+ }
+ if (this._options.paste.targetElement && this._options.paste.promptForName) {
+ if (qq.PasteSupport) {
+ this._setupPastePrompt();
+ } else {
+ this.log("Paste support module not found.", "error");
+ }
+ }
+ this._totalFilesInBatch = 0;
+ this._filesInBatchAddedToUi = 0;
+ }
+ };
+ qq.extend(qq.FineUploader.prototype, qq.basePublicApi);
+ qq.extend(qq.FineUploader.prototype, qq.basePrivateApi);
+ qq.extend(qq.FineUploader.prototype, qq.uiPublicApi);
+ qq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);
+ qq.Templating = function(spec) {
+ "use strict";
+ var FILE_ID_ATTR = "qq-file-id", FILE_CLASS_PREFIX = "qq-file-id-", THUMBNAIL_MAX_SIZE_ATTR = "qq-max-size", THUMBNAIL_SERVER_SCALE_ATTR = "qq-server-scale", HIDE_DROPZONE_ATTR = "qq-hide-dropzone", DROPZPONE_TEXT_ATTR = "qq-drop-area-text", IN_PROGRESS_CLASS = "qq-in-progress", HIDDEN_FOREVER_CLASS = "qq-hidden-forever", fileBatch = {
+ content: document.createDocumentFragment(),
+ map: {}
+ }, isCancelDisabled = false, generatedThumbnails = 0, thumbnailQueueMonitorRunning = false, thumbGenerationQueue = [], thumbnailMaxSize = -1, options = {
+ log: null,
+ limits: {
+ maxThumbs: 0,
+ timeBetweenThumbs: 750
+ },
+ templateIdOrEl: "qq-template",
+ containerEl: null,
+ fileContainerEl: null,
+ button: null,
+ imageGenerator: null,
+ classes: {
+ hide: "qq-hide",
+ editable: "qq-editable"
+ },
+ placeholders: {
+ waitUntilUpdate: false,
+ thumbnailNotAvailable: null,
+ waitingForThumbnail: null
+ },
+ text: {
+ paused: "Paused"
+ }
+ }, selectorClasses = {
+ button: "qq-upload-button-selector",
+ alertDialog: "qq-alert-dialog-selector",
+ dialogCancelButton: "qq-cancel-button-selector",
+ confirmDialog: "qq-confirm-dialog-selector",
+ dialogMessage: "qq-dialog-message-selector",
+ dialogOkButton: "qq-ok-button-selector",
+ promptDialog: "qq-prompt-dialog-selector",
+ uploader: "qq-uploader-selector",
+ drop: "qq-upload-drop-area-selector",
+ list: "qq-upload-list-selector",
+ progressBarContainer: "qq-progress-bar-container-selector",
+ progressBar: "qq-progress-bar-selector",
+ totalProgressBarContainer: "qq-total-progress-bar-container-selector",
+ totalProgressBar: "qq-total-progress-bar-selector",
+ file: "qq-upload-file-selector",
+ spinner: "qq-upload-spinner-selector",
+ size: "qq-upload-size-selector",
+ cancel: "qq-upload-cancel-selector",
+ pause: "qq-upload-pause-selector",
+ continueButton: "qq-upload-continue-selector",
+ deleteButton: "qq-upload-delete-selector",
+ retry: "qq-upload-retry-selector",
+ statusText: "qq-upload-status-text-selector",
+ editFilenameInput: "qq-edit-filename-selector",
+ editNameIcon: "qq-edit-filename-icon-selector",
+ dropText: "qq-upload-drop-area-text-selector",
+ dropProcessing: "qq-drop-processing-selector",
+ dropProcessingSpinner: "qq-drop-processing-spinner-selector",
+ thumbnail: "qq-thumbnail-selector"
+ }, previewGeneration = {}, cachedThumbnailNotAvailableImg = new qq.Promise(), cachedWaitingForThumbnailImg = new qq.Promise(), log, isEditElementsExist, isRetryElementExist, templateHtml, container, fileList, showThumbnails, serverScale, cacheThumbnailPlaceholders = function() {
+ var notAvailableUrl = options.placeholders.thumbnailNotAvailable, waitingUrl = options.placeholders.waitingForThumbnail, spec = {
+ maxSize: thumbnailMaxSize,
+ scale: serverScale
+ };
+ if (showThumbnails) {
+ if (notAvailableUrl) {
+ options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(function(updatedImg) {
+ cachedThumbnailNotAvailableImg.success(updatedImg);
+ }, function() {
+ cachedThumbnailNotAvailableImg.failure();
+ log("Problem loading 'not available' placeholder image at " + notAvailableUrl, "error");
+ });
+ } else {
+ cachedThumbnailNotAvailableImg.failure();
+ }
+ if (waitingUrl) {
+ options.imageGenerator.generate(waitingUrl, new Image(), spec).then(function(updatedImg) {
+ cachedWaitingForThumbnailImg.success(updatedImg);
+ }, function() {
+ cachedWaitingForThumbnailImg.failure();
+ log("Problem loading 'waiting for thumbnail' placeholder image at " + waitingUrl, "error");
+ });
+ } else {
+ cachedWaitingForThumbnailImg.failure();
+ }
+ }
+ }, displayWaitingImg = function(thumbnail) {
+ var waitingImgPlacement = new qq.Promise();
+ cachedWaitingForThumbnailImg.then(function(img) {
+ maybeScalePlaceholderViaCss(img, thumbnail);
+ if (!thumbnail.src) {
+ thumbnail.src = img.src;
+ thumbnail.onload = function() {
+ thumbnail.onload = null;
+ show(thumbnail);
+ waitingImgPlacement.success();
+ };
+ } else {
+ waitingImgPlacement.success();
+ }
+ }, function() {
+ hide(thumbnail);
+ waitingImgPlacement.success();
+ });
+ return waitingImgPlacement;
+ }, generateNewPreview = function(id, blob, spec) {
+ var thumbnail = getThumbnail(id);
+ log("Generating new thumbnail for " + id);
+ blob.qqThumbnailId = id;
+ return options.imageGenerator.generate(blob, thumbnail, spec).then(function() {
+ generatedThumbnails++;
+ show(thumbnail);
+ previewGeneration[id].success();
+ }, function() {
+ previewGeneration[id].failure();
+ if (!options.placeholders.waitUntilUpdate) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ }
+ });
+ }, generateNextQueuedPreview = function() {
+ if (thumbGenerationQueue.length) {
+ thumbnailQueueMonitorRunning = true;
+ var queuedThumbRequest = thumbGenerationQueue.shift();
+ if (queuedThumbRequest.update) {
+ processUpdateQueuedPreviewRequest(queuedThumbRequest);
+ } else {
+ processNewQueuedPreviewRequest(queuedThumbRequest);
+ }
+ } else {
+ thumbnailQueueMonitorRunning = false;
+ }
+ }, getCancel = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.cancel);
+ }, getContinue = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.continueButton);
+ }, getDialog = function(type) {
+ return getTemplateEl(container, selectorClasses[type + "Dialog"]);
+ }, getDelete = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.deleteButton);
+ }, getDropProcessing = function() {
+ return getTemplateEl(container, selectorClasses.dropProcessing);
+ }, getEditIcon = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.editNameIcon);
+ }, getFile = function(id) {
+ return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);
+ }, getFilename = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.file);
+ }, getPause = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.pause);
+ }, getProgress = function(id) {
+ if (id == null) {
+ return getTemplateEl(container, selectorClasses.totalProgressBarContainer) || getTemplateEl(container, selectorClasses.totalProgressBar);
+ }
+ return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) || getTemplateEl(getFile(id), selectorClasses.progressBar);
+ }, getRetry = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.retry);
+ }, getSize = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.size);
+ }, getSpinner = function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.spinner);
+ }, getTemplateEl = function(context, cssClass) {
+ return context && qq(context).getFirstByClass(cssClass);
+ }, getThumbnail = function(id) {
+ return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);
+ }, hide = function(el) {
+ el && qq(el).addClass(options.classes.hide);
+ }, maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {
+ var maxWidth = placeholder.style.maxWidth, maxHeight = placeholder.style.maxHeight;
+ if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {
+ qq(thumbnail).css({
+ maxWidth: maxWidth,
+ maxHeight: maxHeight
+ });
+ }
+ }, maybeSetDisplayNotAvailableImg = function(id, thumbnail) {
+ var previewing = previewGeneration[id] || new qq.Promise().failure(), notAvailableImgPlacement = new qq.Promise();
+ cachedThumbnailNotAvailableImg.then(function(img) {
+ previewing.then(function() {
+ notAvailableImgPlacement.success();
+ }, function() {
+ maybeScalePlaceholderViaCss(img, thumbnail);
+ thumbnail.onload = function() {
+ thumbnail.onload = null;
+ notAvailableImgPlacement.success();
+ };
+ thumbnail.src = img.src;
+ show(thumbnail);
+ });
+ });
+ return notAvailableImgPlacement;
+ }, parseAndGetTemplate = function() {
+ var scriptEl, scriptHtml, fileListNode, tempTemplateEl, fileListHtml, defaultButton, dropArea, thumbnail, dropProcessing, dropTextEl, uploaderEl;
+ log("Parsing template");
+ if (options.templateIdOrEl == null) {
+ throw new Error("You MUST specify either a template element or ID!");
+ }
+ if (qq.isString(options.templateIdOrEl)) {
+ scriptEl = document.getElementById(options.templateIdOrEl);
+ if (scriptEl === null) {
+ throw new Error(qq.format("Cannot find template script at ID '{}'!", options.templateIdOrEl));
+ }
+ scriptHtml = scriptEl.innerHTML;
+ } else {
+ if (options.templateIdOrEl.innerHTML === undefined) {
+ throw new Error("You have specified an invalid value for the template option! " + "It must be an ID or an Element.");
+ }
+ scriptHtml = options.templateIdOrEl.innerHTML;
+ }
+ scriptHtml = qq.trimStr(scriptHtml);
+ tempTemplateEl = document.createElement("div");
+ tempTemplateEl.appendChild(qq.toElement(scriptHtml));
+ uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);
+ if (options.button) {
+ defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);
+ if (defaultButton) {
+ qq(defaultButton).remove();
+ }
+ }
+ if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {
+ dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);
+ if (dropProcessing) {
+ qq(dropProcessing).remove();
+ }
+ }
+ dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);
+ if (dropArea && !qq.DragAndDrop) {
+ log("DnD module unavailable.", "info");
+ qq(dropArea).remove();
+ }
+ if (!qq.supportedFeatures.fileDrop) {
+ uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);
+ if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {
+ qq(dropArea).css({
+ display: "none"
+ });
+ }
+ } else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {
+ dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);
+ dropTextEl && qq(dropTextEl).remove();
+ }
+ thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);
+ if (!showThumbnails) {
+ thumbnail && qq(thumbnail).remove();
+ } else if (thumbnail) {
+ thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));
+ thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;
+ serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);
+ }
+ showThumbnails = showThumbnails && thumbnail;
+ isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;
+ isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;
+ fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);
+ if (fileListNode == null) {
+ throw new Error("Could not find the file list container in the template!");
+ }
+ fileListHtml = fileListNode.innerHTML;
+ fileListNode.innerHTML = "";
+ if (tempTemplateEl.getElementsByTagName("DIALOG").length) {
+ document.createElement("dialog");
+ }
+ log("Template parsing complete");
+ return {
+ template: qq.trimStr(tempTemplateEl.innerHTML),
+ fileTemplate: qq.trimStr(fileListHtml)
+ };
+ }, prependFile = function(el, index, fileList) {
+ var parentEl = fileList, beforeEl = parentEl.firstChild;
+ if (index > 0) {
+ beforeEl = qq(parentEl).children()[index].nextSibling;
+ }
+ parentEl.insertBefore(el, beforeEl);
+ }, processNewQueuedPreviewRequest = function(queuedThumbRequest) {
+ var id = queuedThumbRequest.id, optFileOrBlob = queuedThumbRequest.optFileOrBlob, relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId, thumbnail = getThumbnail(id), spec = {
+ customResizeFunction: queuedThumbRequest.customResizeFunction,
+ maxSize: thumbnailMaxSize,
+ orient: true,
+ scale: true
+ };
+ if (qq.supportedFeatures.imagePreviews) {
+ if (thumbnail) {
+ if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ } else {
+ displayWaitingImg(thumbnail).done(function() {
+ previewGeneration[id] = new qq.Promise();
+ previewGeneration[id].done(function() {
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ });
+ if (relatedThumbnailId != null) {
+ useCachedPreview(id, relatedThumbnailId);
+ } else {
+ generateNewPreview(id, optFileOrBlob, spec);
+ }
+ });
+ }
+ } else {
+ generateNextQueuedPreview();
+ }
+ } else if (thumbnail) {
+ displayWaitingImg(thumbnail);
+ generateNextQueuedPreview();
+ }
+ }, processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {
+ var id = queuedThumbRequest.id, thumbnailUrl = queuedThumbRequest.thumbnailUrl, showWaitingImg = queuedThumbRequest.showWaitingImg, thumbnail = getThumbnail(id), spec = {
+ customResizeFunction: queuedThumbRequest.customResizeFunction,
+ scale: serverScale,
+ maxSize: thumbnailMaxSize
+ };
+ if (thumbnail) {
+ if (thumbnailUrl) {
+ if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ } else {
+ if (showWaitingImg) {
+ displayWaitingImg(thumbnail);
+ }
+ return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(function() {
+ show(thumbnail);
+ generatedThumbnails++;
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ }, function() {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);
+ });
+ }
+ } else {
+ maybeSetDisplayNotAvailableImg(id, thumbnail);
+ generateNextQueuedPreview();
+ }
+ }
+ }, setProgressBarWidth = function(id, percent) {
+ var bar = getProgress(id), progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;
+ if (bar && !qq(bar).hasClass(progressBarSelector)) {
+ bar = qq(bar).getFirstByClass(progressBarSelector);
+ }
+ if (bar) {
+ qq(bar).css({
+ width: percent + "%"
+ });
+ bar.setAttribute("aria-valuenow", percent);
+ }
+ }, show = function(el) {
+ el && qq(el).removeClass(options.classes.hide);
+ }, useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {
+ var targetThumbnail = getThumbnail(targetThumbnailId), cachedThumbnail = getThumbnail(cachedThumbnailId);
+ log(qq.format("ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));
+ previewGeneration[cachedThumbnailId].then(function() {
+ generatedThumbnails++;
+ previewGeneration[targetThumbnailId].success();
+ log(qq.format("Now using previously generated thumbnail created for ID {} on ID {}.", cachedThumbnailId, targetThumbnailId));
+ targetThumbnail.src = cachedThumbnail.src;
+ show(targetThumbnail);
+ }, function() {
+ previewGeneration[targetThumbnailId].failure();
+ if (!options.placeholders.waitUntilUpdate) {
+ maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);
+ }
+ });
+ };
+ qq.extend(options, spec);
+ log = options.log;
+ if (!qq.supportedFeatures.imagePreviews) {
+ options.limits.timeBetweenThumbs = 0;
+ options.limits.maxThumbs = 0;
+ }
+ container = options.containerEl;
+ showThumbnails = options.imageGenerator !== undefined;
+ templateHtml = parseAndGetTemplate();
+ cacheThumbnailPlaceholders();
+ qq.extend(this, {
+ render: function() {
+ log("Rendering template in DOM.");
+ generatedThumbnails = 0;
+ container.innerHTML = templateHtml.template;
+ hide(getDropProcessing());
+ this.hideTotalProgress();
+ fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);
+ log("Template rendering complete");
+ },
+ renderFailure: function(message) {
+ var cantRenderEl = qq.toElement(message);
+ container.innerHTML = "";
+ container.appendChild(cantRenderEl);
+ },
+ reset: function() {
+ this.render();
+ },
+ clearFiles: function() {
+ fileList.innerHTML = "";
+ },
+ disableCancel: function() {
+ isCancelDisabled = true;
+ },
+ addFile: function(id, name, prependInfo, hideForever, batch) {
+ var fileEl = qq.toElement(templateHtml.fileTemplate), fileNameEl = getTemplateEl(fileEl, selectorClasses.file), uploaderEl = getTemplateEl(container, selectorClasses.uploader), fileContainer = batch ? fileBatch.content : fileList, thumb;
+ if (batch) {
+ fileBatch.map[id] = fileEl;
+ }
+ qq(fileEl).addClass(FILE_CLASS_PREFIX + id);
+ uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);
+ if (fileNameEl) {
+ qq(fileNameEl).setText(name);
+ fileNameEl.setAttribute("title", name);
+ }
+ fileEl.setAttribute(FILE_ID_ATTR, id);
+ if (prependInfo) {
+ prependFile(fileEl, prependInfo.index, fileContainer);
+ } else {
+ fileContainer.appendChild(fileEl);
+ }
+ if (hideForever) {
+ fileEl.style.display = "none";
+ qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);
+ } else {
+ hide(getProgress(id));
+ hide(getSize(id));
+ hide(getDelete(id));
+ hide(getRetry(id));
+ hide(getPause(id));
+ hide(getContinue(id));
+ if (isCancelDisabled) {
+ this.hideCancel(id);
+ }
+ thumb = getThumbnail(id);
+ if (thumb && !thumb.src) {
+ cachedWaitingForThumbnailImg.then(function(waitingImg) {
+ thumb.src = waitingImg.src;
+ if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {
+ qq(thumb).css({
+ maxHeight: waitingImg.style.maxHeight,
+ maxWidth: waitingImg.style.maxWidth
+ });
+ }
+ show(thumb);
+ });
+ }
+ }
+ },
+ addFileToCache: function(id, name, prependInfo, hideForever) {
+ this.addFile(id, name, prependInfo, hideForever, true);
+ },
+ addCacheToDom: function() {
+ fileList.appendChild(fileBatch.content);
+ fileBatch.content = document.createDocumentFragment();
+ fileBatch.map = {};
+ },
+ removeFile: function(id) {
+ qq(getFile(id)).remove();
+ },
+ getFileId: function(el) {
+ var currentNode = el;
+ if (currentNode) {
+ while (currentNode.getAttribute(FILE_ID_ATTR) == null) {
+ currentNode = currentNode.parentNode;
+ }
+ return parseInt(currentNode.getAttribute(FILE_ID_ATTR));
+ }
+ },
+ getFileList: function() {
+ return fileList;
+ },
+ markFilenameEditable: function(id) {
+ var filename = getFilename(id);
+ filename && qq(filename).addClass(options.classes.editable);
+ },
+ updateFilename: function(id, name) {
+ var filenameEl = getFilename(id);
+ if (filenameEl) {
+ qq(filenameEl).setText(name);
+ filenameEl.setAttribute("title", name);
+ }
+ },
+ hideFilename: function(id) {
+ hide(getFilename(id));
+ },
+ showFilename: function(id) {
+ show(getFilename(id));
+ },
+ isFileName: function(el) {
+ return qq(el).hasClass(selectorClasses.file);
+ },
+ getButton: function() {
+ return options.button || getTemplateEl(container, selectorClasses.button);
+ },
+ hideDropProcessing: function() {
+ hide(getDropProcessing());
+ },
+ showDropProcessing: function() {
+ show(getDropProcessing());
+ },
+ getDropZone: function() {
+ return getTemplateEl(container, selectorClasses.drop);
+ },
+ isEditFilenamePossible: function() {
+ return isEditElementsExist;
+ },
+ hideRetry: function(id) {
+ hide(getRetry(id));
+ },
+ isRetryPossible: function() {
+ return isRetryElementExist;
+ },
+ showRetry: function(id) {
+ show(getRetry(id));
+ },
+ getFileContainer: function(id) {
+ return getFile(id);
+ },
+ showEditIcon: function(id) {
+ var icon = getEditIcon(id);
+ icon && qq(icon).addClass(options.classes.editable);
+ },
+ isHiddenForever: function(id) {
+ return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);
+ },
+ hideEditIcon: function(id) {
+ var icon = getEditIcon(id);
+ icon && qq(icon).removeClass(options.classes.editable);
+ },
+ isEditIcon: function(el) {
+ return qq(el).hasClass(selectorClasses.editNameIcon, true);
+ },
+ getEditInput: function(id) {
+ return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);
+ },
+ isEditInput: function(el) {
+ return qq(el).hasClass(selectorClasses.editFilenameInput, true);
+ },
+ updateProgress: function(id, loaded, total) {
+ var bar = getProgress(id), percent;
+ if (bar && total > 0) {
+ percent = Math.round(loaded / total * 100);
+ if (percent === 100) {
+ hide(bar);
+ } else {
+ show(bar);
+ }
+ setProgressBarWidth(id, percent);
+ }
+ },
+ updateTotalProgress: function(loaded, total) {
+ this.updateProgress(null, loaded, total);
+ },
+ hideProgress: function(id) {
+ var bar = getProgress(id);
+ bar && hide(bar);
+ },
+ hideTotalProgress: function() {
+ this.hideProgress();
+ },
+ resetProgress: function(id) {
+ setProgressBarWidth(id, 0);
+ this.hideTotalProgress(id);
+ },
+ resetTotalProgress: function() {
+ this.resetProgress();
+ },
+ showCancel: function(id) {
+ if (!isCancelDisabled) {
+ var cancel = getCancel(id);
+ cancel && qq(cancel).removeClass(options.classes.hide);
+ }
+ },
+ hideCancel: function(id) {
+ hide(getCancel(id));
+ },
+ isCancel: function(el) {
+ return qq(el).hasClass(selectorClasses.cancel, true);
+ },
+ allowPause: function(id) {
+ show(getPause(id));
+ hide(getContinue(id));
+ },
+ uploadPaused: function(id) {
+ this.setStatusText(id, options.text.paused);
+ this.allowContinueButton(id);
+ hide(getSpinner(id));
+ },
+ hidePause: function(id) {
+ hide(getPause(id));
+ },
+ isPause: function(el) {
+ return qq(el).hasClass(selectorClasses.pause, true);
+ },
+ isContinueButton: function(el) {
+ return qq(el).hasClass(selectorClasses.continueButton, true);
+ },
+ allowContinueButton: function(id) {
+ show(getContinue(id));
+ hide(getPause(id));
+ },
+ uploadContinued: function(id) {
+ this.setStatusText(id, "");
+ this.allowPause(id);
+ show(getSpinner(id));
+ },
+ showDeleteButton: function(id) {
+ show(getDelete(id));
+ },
+ hideDeleteButton: function(id) {
+ hide(getDelete(id));
+ },
+ isDeleteButton: function(el) {
+ return qq(el).hasClass(selectorClasses.deleteButton, true);
+ },
+ isRetry: function(el) {
+ return qq(el).hasClass(selectorClasses.retry, true);
+ },
+ updateSize: function(id, text) {
+ var size = getSize(id);
+ if (size) {
+ show(size);
+ qq(size).setText(text);
+ }
+ },
+ setStatusText: function(id, text) {
+ var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);
+ if (textEl) {
+ if (text == null) {
+ qq(textEl).clearText();
+ } else {
+ qq(textEl).setText(text);
+ }
+ }
+ },
+ hideSpinner: function(id) {
+ qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);
+ hide(getSpinner(id));
+ },
+ showSpinner: function(id) {
+ qq(getFile(id)).addClass(IN_PROGRESS_CLASS);
+ show(getSpinner(id));
+ },
+ generatePreview: function(id, optFileOrBlob, customResizeFunction) {
+ if (!this.isHiddenForever(id)) {
+ thumbGenerationQueue.push({
+ id: id,
+ customResizeFunction: customResizeFunction,
+ optFileOrBlob: optFileOrBlob
+ });
+ !thumbnailQueueMonitorRunning && generateNextQueuedPreview();
+ }
+ },
+ updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {
+ if (!this.isHiddenForever(id)) {
+ thumbGenerationQueue.push({
+ customResizeFunction: customResizeFunction,
+ update: true,
+ id: id,
+ thumbnailUrl: thumbnailUrl,
+ showWaitingImg: showWaitingImg
+ });
+ !thumbnailQueueMonitorRunning && generateNextQueuedPreview();
+ }
+ },
+ hasDialog: function(type) {
+ return qq.supportedFeatures.dialogElement && !!getDialog(type);
+ },
+ showDialog: function(type, message, defaultValue) {
+ var dialog = getDialog(type), messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage), inputEl = dialog.getElementsByTagName("INPUT")[0], cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton), okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton), promise = new qq.Promise(), closeHandler = function() {
+ cancelBtn.removeEventListener("click", cancelClickHandler);
+ okBtn && okBtn.removeEventListener("click", okClickHandler);
+ promise.failure();
+ }, cancelClickHandler = function() {
+ cancelBtn.removeEventListener("click", cancelClickHandler);
+ dialog.close();
+ }, okClickHandler = function() {
+ dialog.removeEventListener("close", closeHandler);
+ okBtn.removeEventListener("click", okClickHandler);
+ dialog.close();
+ promise.success(inputEl && inputEl.value);
+ };
+ dialog.addEventListener("close", closeHandler);
+ cancelBtn.addEventListener("click", cancelClickHandler);
+ okBtn && okBtn.addEventListener("click", okClickHandler);
+ if (inputEl) {
+ inputEl.value = defaultValue;
+ }
+ messageEl.textContent = message;
+ dialog.showModal();
+ return promise;
+ }
+ });
+ };
+ qq.UiEventHandler = function(s, protectedApi) {
+ "use strict";
+ var disposer = new qq.DisposeSupport(), spec = {
+ eventType: "click",
+ attachTo: null,
+ onHandled: function(target, event) {}
+ };
+ qq.extend(this, {
+ addHandler: function(element) {
+ addHandler(element);
+ },
+ dispose: function() {
+ disposer.dispose();
+ }
+ });
+ function addHandler(element) {
+ disposer.attach(element, spec.eventType, function(event) {
+ event = event || window.event;
+ var target = event.target || event.srcElement;
+ spec.onHandled(target, event);
+ });
+ }
+ qq.extend(protectedApi, {
+ getFileIdFromItem: function(item) {
+ return item.qqFileId;
+ },
+ getDisposeSupport: function() {
+ return disposer;
+ }
+ });
+ qq.extend(spec, s);
+ if (spec.attachTo) {
+ addHandler(spec.attachTo);
+ }
+ };
+ qq.FileButtonsClickHandler = function(s) {
+ "use strict";
+ var inheritedInternalApi = {}, spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ onDeleteFile: function(fileId) {},
+ onCancel: function(fileId) {},
+ onRetry: function(fileId) {},
+ onPause: function(fileId) {},
+ onContinue: function(fileId) {},
+ onGetName: function(fileId) {}
+ }, buttonHandlers = {
+ cancel: function(id) {
+ spec.onCancel(id);
+ },
+ retry: function(id) {
+ spec.onRetry(id);
+ },
+ deleteButton: function(id) {
+ spec.onDeleteFile(id);
+ },
+ pause: function(id) {
+ spec.onPause(id);
+ },
+ continueButton: function(id) {
+ spec.onContinue(id);
+ }
+ };
+ function examineEvent(target, event) {
+ qq.each(buttonHandlers, function(buttonType, handler) {
+ var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1), fileId;
+ if (spec.templating["is" + firstLetterCapButtonType](target)) {
+ fileId = spec.templating.getFileId(target);
+ qq.preventDefault(event);
+ spec.log(qq.format("Detected valid file button click event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ handler(fileId);
+ return false;
+ }
+ });
+ }
+ qq.extend(spec, s);
+ spec.eventType = "click";
+ spec.onHandled = examineEvent;
+ spec.attachTo = spec.templating.getFileList();
+ qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameClickHandler = function(s) {
+ "use strict";
+ var inheritedInternalApi = {}, spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ classes: {
+ file: "qq-upload-file",
+ editNameIcon: "qq-edit-filename-icon"
+ },
+ onGetUploadStatus: function(fileId) {},
+ onGetName: function(fileId) {}
+ };
+ qq.extend(spec, s);
+ function examineEvent(target, event) {
+ if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {
+ var fileId = spec.templating.getFileId(target), status = spec.onGetUploadStatus(fileId);
+ if (status === qq.status.SUBMITTED) {
+ spec.log(qq.format("Detected valid filename click event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ qq.preventDefault(event);
+ inheritedInternalApi.handleFilenameEdit(fileId, target, true);
+ }
+ }
+ }
+ spec.eventType = "click";
+ spec.onHandled = examineEvent;
+ qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {
+ "use strict";
+ var spec = {
+ templating: null,
+ onGetUploadStatus: function(fileId) {},
+ log: function(message, lvl) {}
+ };
+ if (!inheritedInternalApi) {
+ inheritedInternalApi = {};
+ }
+ function handleInputFocus(target, event) {
+ if (spec.templating.isEditInput(target)) {
+ var fileId = spec.templating.getFileId(target), status = spec.onGetUploadStatus(fileId);
+ if (status === qq.status.SUBMITTED) {
+ spec.log(qq.format("Detected valid filename input focus event on file '{}', ID: {}.", spec.onGetName(fileId), fileId));
+ inheritedInternalApi.handleFilenameEdit(fileId, target);
+ }
+ }
+ }
+ spec.eventType = "focusin";
+ spec.onHandled = handleInputFocus;
+ qq.extend(spec, s);
+ qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));
+ };
+ qq.FilenameInputFocusHandler = function(spec) {
+ "use strict";
+ spec.eventType = "focus";
+ spec.attachTo = null;
+ qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));
+ };
+ qq.FilenameEditHandler = function(s, inheritedInternalApi) {
+ "use strict";
+ var spec = {
+ templating: null,
+ log: function(message, lvl) {},
+ onGetUploadStatus: function(fileId) {},
+ onGetName: function(fileId) {},
+ onSetName: function(fileId, newName) {},
+ onEditingStatusChange: function(fileId, isEditing) {}
+ };
+ function getFilenameSansExtension(fileId) {
+ var filenameSansExt = spec.onGetName(fileId), extIdx = filenameSansExt.lastIndexOf(".");
+ if (extIdx > 0) {
+ filenameSansExt = filenameSansExt.substr(0, extIdx);
+ }
+ return filenameSansExt;
+ }
+ function getOriginalExtension(fileId) {
+ var origName = spec.onGetName(fileId);
+ return qq.getExtension(origName);
+ }
+ function handleNameUpdate(newFilenameInputEl, fileId) {
+ var newName = newFilenameInputEl.value, origExtension;
+ if (newName !== undefined && qq.trimStr(newName).length > 0) {
+ origExtension = getOriginalExtension(fileId);
+ if (origExtension !== undefined) {
+ newName = newName + "." + origExtension;
+ }
+ spec.onSetName(fileId, newName);
+ }
+ spec.onEditingStatusChange(fileId, false);
+ }
+ function registerInputBlurHandler(inputEl, fileId) {
+ inheritedInternalApi.getDisposeSupport().attach(inputEl, "blur", function() {
+ handleNameUpdate(inputEl, fileId);
+ });
+ }
+ function registerInputEnterKeyHandler(inputEl, fileId) {
+ inheritedInternalApi.getDisposeSupport().attach(inputEl, "keyup", function(event) {
+ var code = event.keyCode || event.which;
+ if (code === 13) {
+ handleNameUpdate(inputEl, fileId);
+ }
+ });
+ }
+ qq.extend(spec, s);
+ spec.attachTo = spec.templating.getFileList();
+ qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));
+ qq.extend(inheritedInternalApi, {
+ handleFilenameEdit: function(id, target, focusInput) {
+ var newFilenameInputEl = spec.templating.getEditInput(id);
+ spec.onEditingStatusChange(id, true);
+ newFilenameInputEl.value = getFilenameSansExtension(id);
+ if (focusInput) {
+ newFilenameInputEl.focus();
+ }
+ registerInputBlurHandler(newFilenameInputEl, id);
+ registerInputEnterKeyHandler(newFilenameInputEl, id);
+ }
+ });
+ };
+})(window);
+//# sourceMappingURL=fine-uploader.js.map
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader.js.map b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.js.map
new file mode 100644
index 000000000000..dcbe79b926cd
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/error/error.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/blob-proxy.js","../client/js/button.js","../client/js/upload-data.js","../client/js/uploader.basic.api.js","../client/js/uploader.basic.js","../client/js/ajax.requester.js","../client/js/upload-handler/upload.handler.js","../client/js/upload-handler/upload.handler.controller.js","../client/js/window.receive.message.js","../client/js/upload-handler/form.upload.handler.js","../client/js/upload-handler/xhr.upload.handler.js","../client/js/deletefile.ajax.requester.js","../client/js/image-support/megapix-image.js","../client/js/image-support/image.js","../client/js/image-support/exif.js","../client/js/identify.js","../client/js/image-support/validation.image.js","../client/js/session.js","../client/js/session.ajax.requester.js","../client/js/image-support/scaler.js","../client/js/third-party/ExifRestorer.js","../client/js/total-progress.js","../client/js/paste.js","../client/js/form-support.js","../client/js/traditional/traditional.form.upload.handler.js","../client/js/traditional/traditional.xhr.upload.handler.js","../client/js/traditional/all-chunks-done.ajax.requester.js","../client/js/dnd.js","../client/js/uploader.api.js","../client/js/uploader.js","../client/js/templating.js","../client/js/ui.handler.events.js","../client/js/ui.handler.click.filebuttons.js","../client/js/ui.handler.click.filename.js","../client/js/ui.handler.focusin.filenameinput.js","../client/js/ui.handler.focus.filenameinput.js","../client/js/ui.handler.edit.filename.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","intArray","mimeString","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","testSupportsFileInputElement","supported","tempInput","disabled","ex","isChrome21OrHigher","match","isChrome14OrHigher","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","BlobProxy","referenceBlob","onCreate","create","UploadButton","o","self","disposeSupport","options","acceptFiles","focusClass","folders","hoverClass","ios8BrowserCrashWorkaround","onChange","title","buttonId","createInput","BUTTON_ID_ATTR_NAME","setMultiple","position","right","top","fontFamily","fontSize","margin","padding","cursor","height","overflow","direction","getInput","getButtonId","isMultiple","optInput","removeAttribute","setAcceptFiles","reset","UploadData","uploaderProxy","byUuid","byStatus","byProxyGroupId","byBatchId","getDataByIds","idOrIds","entries","id","getDataByUuids","uuids","uuid","getDataByStatus","status","statusResults","statuses","index","statusEnum","statusResultIndexes","dataIndex","addFile","spec","SUBMITTING","originalName","size","batchId","proxyGroupId","onStatusChange","retrieve","optionalFilter","setStatus","newStatus","oldStatus","byStatusOldStatusIndex","splice","uuidChanged","newUuid","oldUuid","updateName","newName","updateSize","newSize","setParentId","targetId","parentId","getIdsInProxyGroup","getIdsInBatch","SUBMITTED","REJECTED","QUEUED","CANCELED","PAUSED","UPLOADING","UPLOAD_RETRYING","UPLOAD_SUCCESSFUL","UPLOAD_FAILED","DELETE_FAILED","DELETING","DELETED","basePublicApi","addBlobs","blobDataOrArray","params","endpoint","addFiles","addInitialFiles","cannedFileList","cannedFile","_addCannedFile","_maybeHandleIos8SafariWorkaround","_storedIds","_currentBatchId","processBlob","_handleNewFile","_options","blobs","defaultName","verifiedFiles","processBlobData","blobData","processCanvas","processCanvasData","canvasData","normalizedQuality","processFileOrInput","fileOrInput","files","file","normalizeData","fileContainer","_prepareItemsForUpload","cancel","_handler","cancelAll","storedIdsCopy","storedFileId","clearStoredFiles","continueUpload","uploadData","_uploadData","enabled","getName","_uploadFile","deleteFile","_onSubmitDelete","doesExist","fileOrBlobId","isValid","drawThumbnail","fileId","imgOrCanvas","maxSize","fromServer","customResizeFunction","promiseToReturn","fileOrUrl","_imageGenerator","_thumbnailUrls","scale","getFile","container","generate","modifiedContainer","reason","getButton","_getButton","_buttonIdsForFileIds","getEndpoint","_endpointStore","get","getInProgress","getParentId","uploadDataEntry","getUploads","getResumableFilesData","getSize","getNetUploads","_netUploaded","getRemainingAllowedItems","allowedItems","_currentItemLimit","_netUploadedOrQueued","getUuid","debug","pauseUpload","_autoRetries","_retryTimeouts","_preventRetries","_buttons","button","_paramsStore","_pasteHandler","session","refreshOnReset","_refreshSessionData","_succeededSinceLastAllComplete","_failedSinceLastAllComplete","_totalProgress","retry","_manualRetry","scaleImage","specs","Scaler","setCustomHeaders","headers","_customHeadersStore","set","setDeleteFileCustomHeaders","_deleteFileCustomHeadersStore","setDeleteFileEndpoint","_deleteFileEndpointStore","setDeleteFileParams","_deleteFileParamsStore","setEndpoint","setForm","elementOrId","_updateFormSupportAndParams","setItemLimit","newItemLimit","setName","setParams","setUuid","uploadStoredFiles","_itemError","_uploadStoredFiles","basePrivateApi","sessionData","deleteFileEndpoint","deleteFileParams","thumbnailUrl","_annotateWithButtonId","associatedInput","qqButtonId","_getButtonId","_batchError","callbacks","onError","_createDeleteHandler","DeleteFileAjaxRequester","method","toUpperCase","maxConnections","uuidParamName","request","uuidName","customHeaders","paramsStore","endpointStore","cors","onDelete","_onDelete","onDeleteComplete","xhrOrXdr","isError","_onDeleteComplete","_createPasteHandler","PasteSupport","targetElement","paste","pasteReceived","_handleCheckedCallback","onPasteReceived","_handlePasteSuccess","identifier","_createStore","initialValue","_readOnlyValues_","store","catchall","perIdReadOnlyValues","readOnlyValues","copy","orig","getReadOnlyValues","includeReadOnlyValues","existing","values","addReadOnly","_createUploadDataTracker","_onUploadStatusChange","_maybeAllComplete","setTimeout","_createUploadButton","accept","validation","allowedExtensions","allowMultiple","workarounds","iosEmptyVideos","_isAllowedExtension","classes","buttonFocus","buttonHover","ios8BrowserCrash","inputName","_onInputChange","fileInputTitle","_disposeSupport","_createUploadHandler","additionalOptions","namespace","lastOnProgress","preventRetryParam","preventRetryResponseProperty","onProgress","loaded","total","_onProgress","onComplete","_onComplete","onCancel","cancelFinalizationEffort","_onCancel","onUploadPrep","_onUploadPrep","onUpload","_onUpload","onUploadChunk","chunkData","_onUploadChunk","onUploadChunkSuccess","onResume","onAutoRetry","responseJSON","_onAutoRetry","onUuidChanged","setSize","_setSize","getDataByUuid","isQueued","UploadHandlerController","_fileOrBlobRejected","_formatSize","sizeSymbols","max","toFixed","_generateExtraButtonSpecs","_extraButtonSpecs","extraButtons","extraButtonOptionEntry","extraButtonSpec","_initExtraButton","extraButtonsSpec","_defaultButtonId","buttonOrFileInputOrFile","inputs","fileInput","fileBlobOrInput","_getNotFinished","_getValidationBase","_getValidationDescriptor","fileWrapper","_getValidationDescriptors","fileWrappers","fileDescriptors","_handleCameraAccess","camera","acceptIosCamera","optionRoot","details","callbackRetVal","successParam","newFileWrapperList","actualFile","handler","_customNewFileHandler","_handleNewFileGeneric","addFileToHandler","_trackButton","fileList","extSuppliedName","extension","_initFormSupportAndParams","_formSupport","FormSupport","attachedToForm","getFormInputsAsObject","autoUpload","newAutoUpload","newEndpoint","_isDeletePossible","expected","allowXdr","allowed","valid","allowedExt","extRegex","code","maybeNameOrNames","messages","names","validationBase","extensionsForMessage","placeholderMatch","replacement","allowedExtension","formatFileName","sizeLimit","minSizeLimit","placeholder","_onBeforeManualRetry","notFinished","_onAllComplete","ios8SafariUploads","alert","unsupportedBrowserIos8Safari","_maybeParseAndSendUploadError","response","errorReason","defaultResponseError","_maybeProcessNextItemAfterOnValidateCallback","validItem","stopOnFirstInvalidFile","validationDescriptor","onValidate","_onValidateCallbackSuccess","_onValidateCallbackFailure","successful","failed","onAllComplete","_shouldAutoRetry","retryWaitPeriod","autoAttemptDelay","_onBeforeAutoRetry","itemLimit","onManualRetry","clearTimeout","storedItemIndex","expunge","fileIndex","onIndividualProgress","_onSubmit","_onSubmitCallbackSuccess","_onSubmitted","onSubmitted","_storeForLater","onSuccessCallback","additionalMandatedParams","adjustedOnSuccessCallback","onSubmitDelete","_deleteHandler","sendDelete","_onTotalProgress","onTotalProgress","_onValidateBatchCallbackFailure","_onValidateBatchCallbackSuccess","validationDescriptors","errorMessage","proposedNetFilesUploadedOrQueued","tooManyItemsError","nextIndex","_validateFileOrBlobData","_upload","onValidateBatch","_preventLeaveInProgress","event","onLeave","Session","_session","addFileRecord","refresh","_sessionRequestComplete","onSessionRequestComplete","onNewSize","enableAuto","maxAutoAttempts","formElementOrId","onSubmit","idToUpload","stillSubmitting","validityChecker","allowEmpty","ImageValidation","validate","image","errorCode","_wrapCallbacks","safeCallback","errorMsg","exception","callbackName","callbackFunc","FineUploaderBasic","disableCancelForFormUploads","filenameParam","forceMultipart","paramsInBody","totalFileSizeName","maxHeight","maxWidth","minHeight","minWidth","maybeXhr","maybeXhrOrXdr","attemptNumber","fileOrBlobData","typeError","sizeError","minSizeError","emptyError","noFilesError","maxHeightImageError","maxWidthImageError","minHeightImageError","minWidthImageError","retryFailTooManyItems","concurrent","mandatory","paramNames","partIndex","partByteOffset","chunkSize","totalFileSize","totalParts","partSize","recordsExpireIn","resuming","fileOrBlobName","sendCredentials","interceptSubmit","customResizer","sendOriginal","orient","defaultType","defaultQuality","failureText","includeExif","sizes","ImageGenerator","_scaler","handleNewFile","TotalProgress","entry","AjaxRequester","shouldParamsBeInQueryString","queue","requestData","acceptHeader","validMethods","contentType","mandatedParams","allowXRequestedWithAndCacheControl","successfulResponseCodes","DELETE","PATCH","POST","PUT","GET","onSend","isSimpleMethod","containsNonSimpleHeaders","containsNonSimple","header","isXdr","getCorsAjaxTransport","ontimeout","onprogress","getXhrOrXdr","suppliedXhr","dequeue","nextId","sendRequest","xdrError","isResponseSuccessful","getParams","onDemandParams","additionalParams","optXhr","payload","url","createUrl","additionalQueryParams","getXdrLoadHandler","getXdrErrorHandler","onreadystatechange","getXhrReadyStateChangeHandler","registerForUploadProgress","open","setHeaders","send","stringify","addToPath","readyState","lengthComputable","onDemandHeaders","additionalHeaders","allHeaders","setRequestHeader","responseCode","prepareToSend","initTransport","path","cacheBuster","withPath","appendToPath","withParams","withQueryParams","_additionalQueryParams_","withHeaders","withPayload","thePayload","withCacheBuster","qqtimestamp","Date","getTime","canceled","UploadHandler","proxy","fileState","fileItem","onCancelRetVal","getThirdPartyFileId","_getFileState","_setThirdPartyFileId","thirdPartyFileId","_wasCanceled","controller","chunkingPossible","concurrentChunkingPossible","preventRetryResponse","chunked","chunkIdx","_getChunkData","attemptingResume","chunkProgress","_getChunkDataForCallback","finalize","finalizeChunks","normaizedResponse","normalizeResponse","_maybeDeletePersistedChunkData","cleanup","handleFailure","clearCachedChunk","responseToReport","inProgressIdx","inProgress","remaining","unshift","ignoreFailure","keys","_getXhrs","ckid","ckXhr","abort","_cancelled","moveInProgressToRemaining","connectionManager","free","hasMoreParts","nextPart","nextIdx","_getTotalChunks","reevaluateChunking","sendNext","inProgressChunks","available","uploadChunk","inProgressChunkIdx","_maybePersistChunkedState","clearXhr","_open","_openChunks","_waiting","openChunkEntriesCount","openChunksCount","openChunkIndexes","dontAllowNext","allowNext","waitingIndex","connectionsIndex","getProxyOrBlob","getWaitingOrConnected","waitingOrConnected","chunks","parseInt","isUsingConnection","pop","openChunksEntry","simple","uploadFile","maybeNewUuid","_clearXhrs","getProxy","initHandler","handlerType","traditional","handlerModuleSubtype","_removeExpiredChunkingRecords","isDeferredEligibleForUpload","maybeDefer","generatedBlob","updateBlob","maybeSendDeferredFiles","errorResponse","idsInGroup","uploadedThisId","idInGroup","now","originalResponse","_shouldChunkThisFile","blobToUpload","cancelRetVal","isProxied","isResumable","WindowReceiveMessage","callbackWrapperDetachers","receiveMessage","onMessageCallbackWrapper","stopReceivingMessages","detacher","FormUploadHandler","formHandlerInstanceId","onloadCallbacks","detachLoadEvents","postMessageCallbackTimers","isCors","corsMessageReceiver","expungeFile","iframe","getElementById","_getIframeName","getFileIdForIframeName","iframeName","initIframeForUpload","body","registerPostMessageCallback","_parseJsonResponse","onloadCallback","_detachLoadEvent","_attachLoadEvent","responseDescriptor","contentDocument","_createIframe","_initFormForUpload","targetName","innerHtmlOrMessage","XhrUploadHandler","chunkFiles","resumeEnabled","xhrId","ajaxRequester","_getAjaxRequester","blobOrProxy","_initTempState","_maybePrepareForResume","cachedChunks","tempState","xhrs","ajaxRequesters","responseParser","lastChunkIdx","_getXhr","resumableFilesData","_iterateResumeRecords","notResumable","optInProgress","optRemaining","reverse","paused","totalChunks","parts","newBlob","chunkId","_createXhr","optChunkIdx","_registerXhr","chunkIndex","fileSize","startBytes","endBytes","part","count","startByte","endByte","_getLocalStorageId","formatVersion","_getMimeType","_getPersistableData","ceil","_markNotResumable","localStorageId","removeItem","persistedData","lastUpdated","_registerProgressHandler","progressCalculator","totalSuccessfullyLoadedForFile","loadedForRequest","totalForRequest","estActualChunkLoaded","totalLoadedForFile","chunkLoaded","optAjaxRequester","xhrsId","expirationDays","expirationDate","setDate","getDate","requester","getMandatedParams","_method","detectSubsampling","img","iw","naturalWidth","ih","naturalHeight","ctx","width","getContext","drawImage","getImageData","detectVerticalSquash","sy","ey","py","alpha","ratio","renderImageToDataURL","doSquash","renderImageToCanvas","maybeCalculateDownsampledDimensions","maxPixels","origHeight","origWidth","newHeight","sqrt","newWidth","modifiedDimensions","save","resize","renderImageToCanvasWithCustomResizer","imageHeight","imageWidth","orientation","targetHeight","targetWidth","transformCoordinate","d","tmpCanvas","vertSquashRatio","dw","dh","dy","tmpCtx","sx","dx","clearRect","restore","qqImageRendered","resizeInfo","sourceCanvas","sourceCanvasContext","targetCanvas","translate","rotate","PI","MegaPixImage","srcImage","errorCallback","Image","URL","createObjectURL","webkitURL","src","listeners","imageLoadListeners","render","imgWidth","imgHeight","opt","optionsKey","optionsValue","oldTargetSrc","onrender","isImg","el","isCanvas","isImgCorsSupported","crossOrigin","isCanvasSupported","determineMimeOfFileName","nameWithPath","pathSegments","isCrossOrigin","targetAnchor","targetProtocol","targetHostname","targetPort","href","protocol","port","hostname","location","registerImgLoadListeners","registerCanvasDrawImageListener","registerThumbnailRenderedListener","registered","draw","drawPreview","Identify","megapixErrorHandler","isPreviewable","dummyExif","exif","Exif","mpImg","Orientation","failureMsg","drawOnCanvasOrImgFromUrl","canvasOrImg","tempImg","tempImgRender","rendered","drawOnImgFromUrlWithCssScaling","drawFromUrl","fileBlobOrUrl","_testing","TAG_IDS","TAG_INFO","274","parseLittleEndian","hex","pow","seekToApp1","offset","theOffset","thePromise","segmentLength","getApp1Offset","isLittleEndian","app1Start","getDirEntryCount","littleEndian","getIfd","dirEntries","getDirEntries","ifdHex","getTagValues","TAG_VAL_OFFSET","tagsToFind","vals","idHex","tagsToFindIdx","tagValHex","tagValLength","parser","onParseFailure","app1Offset","dirEntryCount","tagValues","isIdentifiable","magicBytes","questionableBytes","identifiable","magicBytesEntries","magicBytesArrayEntry","previewable","isPreviewableSync","PREVIEWABLE_MIME_TYPES","fileMime","isRecognizedImage","image/jpeg","image/gif","image/png","image/bmp","image/tiff","hasNonZeroLimits","limits","atLeastOne","limit","getWidthHeight","sizeDetermination","getFailingLimit","dimensions","failingLimit","limitName","limitValue","limitMatcher","dimensionPropName","actualValue","validationEffort","isJsonResponseValid","handleFileItems","fileItems","someItemsIgnored","err","refreshEffort","refreshCompleteCallback","requesterOptions","SessionAjaxRequester","queryServer","responseText","includeOriginal","failedToScaleText","_getSortedSizes","getFileRecords","originalFileUuid","originalFileName","originalBlobOrBlobData","records","originalBlob","sizeRecord","outputType","_determineOutputType","requestedType","refType","_getName","_generateScaledImage","failedText","api","scaledIds","originalId","record","blobSize","scaledId","qqparentuuid","qqparentsize","param","scalingEffort","scalingOptions","scaler","referenceType","scaledVersionProperties","startOfExt","versionType","scaledName","scaledExt","nameAppendage","sort","a","b","sourceFile","imageGenerator","scaledImageDataUri","signalSuccess","_insertExifHeader","scaledImageDataUriWithExif","originalImage","reader","insertionEffort","originalImageDataUri","ExifRestorer","readAsDataURL","_dataUriToBlob","_createBlob","KEY_STR","encode64","output","chr1","chr2","chr3","enc1","enc2","enc3","enc4","isNaN","origFileBase64","resizedFileBase64","expectedBase64Header","rawImage","decode64","segments","slice2Segments","exifManipulation","exifArray","getExifArray","newImageArray","insertExif","aBuffer","seg","x","imageData","buf","separatePoint","mae","ato","array","rawImageArray","head","endPoint","base64test","perFileProgress","totalLoaded","totalSize","lastLoadedSent","lastTotalSent","callbackProxy","noRetryableFiles","retryable","none","failedId","updateTotalProgress","onNew","newLoaded","newTotal","oldLoaded","oldTotal","detachPasteHandler","isImage","registerPasteHandler","clipboardData","getAsFile","unregisterPasteHandler","startUpload","formEl","_form2Obj","determineNewEndpoint","validateForm","nativeSubmit","checkValidity","maybeUploadOnSubmit","submit","determineFormEl","notIrrelevantType","irrelevantTypes","radioOrCheckbox","ignoreValue","checked","selectValue","select","selected","elements","getIframeContentJson","doc","innerHtml","contentWindow","nodeValue","createForm","responseFromMessage","multipart","addChunkingSpecificParams","allChunksDoneRequester","AllChunksDoneAjaxRequester","createReadyStateChangedHandler","onUploadOrChunkComplete","getChunksCompleteParams","isErrorUploadResponse","parseResponse","sendChunksCompleteRequest","complete","setParamsAndGetEntityToSend","setUploadHeaders","extraHeaders","toSend","promises","endpointHandler","DragAndDrop","HIDE_ZONES_EVENT_NAME","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","droppedFiles","dropZoneElements","allowMultipleItems","dropActive","uploadDroppedFiles","uploadDropZone","filesAsArray","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","parseEntryPromise","fullPath","indexOfNameInFullPath","qqPath","fileError","isDirectory","getFilesInDirectory","allEntriesRead","entriesLeft","readFailure","accumEntries","existingPromise","dirReader","createReader","readEntries","readSuccess","newEntries","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","dropError","setupDropzone","dropArea","dropZone","UploadDropZone","onEnter","stopPropagation","onLeaveNotDescendants","onDrop","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","relatedTarget","y","setupDragDrop","dropZones","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","targetEl","errorSpecifics","preventDrop","dropOutsideDisabled","dragoverShouldBeCanceled","disableDropOutside","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","isOrSetDropDisabled","isDisabled","triggerHidezonesEvent","hideZonesEvent","triggerUsingOldApi","createEvent","initEvent","CustomEvent","dispatchEvent","attachEvents","effect","elementFromPoint","clientX","clientY","uiPublicApi","_parent","_templating","addCacheToDom","clearFiles","addExtraDropzone","_dnd","removeExtraDropzone","getItemByFileId","isHiddenForever","getFileContainer","_setupDragAndDrop","_totalFilesInBatch","_filesInBatchAddedToUi","_setupClickAndEditEventHandlers","formattedFilename","updateFilename","uploadPaused","continued","uploadContinued","getId","fileContainerOrChildEl","getFileId","getDropTarget","qqDropTarget","uiPrivateApi","_removeFileItem","removeFile","_fileButtonsClickHandler","FileButtonsClickHandler","_bindFileButtonsClickEvent","_focusinEventSupported","_isEditFilenameEnabled","_filenameClickHandler","_bindFilenameClickEvent","_filenameInputFocusInHandler","_bindFilenameInputFocusInEvent","_filenameInputFocusHandler","_bindFilenameInputFocusEvent","dragAndDrop","extraDropzones","templating","defaultDropZone","getDropZone","showDropProcessing","hideDropProcessing","errorData","lvl","onDeleteFile","onRetry","onPause","onContinue","onGetName","isEditFilenamePossible","FilenameClickHandler","FilenameInputFocusHandler","_filenameEditHandler","onGetUploadStatus","onSetName","onEditingStatusChange","isEditing","qqInput","getEditInput","qqFileContainer","hideFilename","hideEditIcon","showFilename","showEditIcon","markFilenameEditable","hideRetry","setStatusText","_classes","retrying","hidePause","FilenameInputFocusInHandler","hideSpinner","resetTotalProgress","reportDirectoryPaths","qqpath","_addToList","addHandler","updateProgress","hideCancel","hideProgress","waitingForResponse","_displayFileSize","parentRetVal","completeUpload","_markFileAsSuccessful","fail","showCancel","isRetryPossible","showRetry","_controlFailureTextDisplay","newResult","showDeleteButton","_maybeUpdateThumbnail","showSpinner","allowPause","retryNumForDisplay","maxAuto","retryNote","_showCancelLink","showAutoRetryNote","autoRetryNote","resetProgress","_onSubmitDeleteSuccess","forceConfirm","_showDeleteConfirm","_sendDeleteRequest","deletingFailedText","hideDeleteButton","deletingStatusText","confirmMessage","deleteRequestArgs","showConfirm","canned","prependData","prependIndex","dontDisplay","hideScaled","prependFiles","disableCancel","_handledProxyGroup","_clearList","addFileToCache","updateThumbnail","thumbnails","generatePreview","fileSizeOnSubmit","loadedSize","sizeForDisplay","_formatProgress","uploadedSize","formatProgress","mode","responseProperty","failureReason","failedUploadTextDisplay","failUpload","enableTooltip","_showTooltip","showMessage","_setupPastePrompt","namePromptMessage","defaultVal","showPrompt","fileStatus","placeholders","waitUntilResponse","FineUploader","listElement","template","editable","tooManyFilesError","unsupportedBrowser","promptForName","maxCount","notAvailablePath","waitingPath","timeBetweenThumbs","hasDialog","showDialog","confirm","defaultValue","prompt","Templating","templateIdOrEl","containerEl","fileContainerEl","maxThumbs","waitUntilUpdate","thumbnailNotAvailable","waitingForThumbnail","renderFailure","FILE_ID_ATTR","FILE_CLASS_PREFIX","THUMBNAIL_MAX_SIZE_ATTR","THUMBNAIL_SERVER_SCALE_ATTR","HIDE_DROPZONE_ATTR","DROPZPONE_TEXT_ATTR","IN_PROGRESS_CLASS","HIDDEN_FOREVER_CLASS","fileBatch","content","createDocumentFragment","map","isCancelDisabled","generatedThumbnails","thumbnailQueueMonitorRunning","thumbGenerationQueue","thumbnailMaxSize","selectorClasses","alertDialog","dialogCancelButton","confirmDialog","dialogMessage","dialogOkButton","promptDialog","uploader","drop","list","progressBarContainer","totalProgressBarContainer","totalProgressBar","spinner","continueButton","deleteButton","statusText","editFilenameInput","editNameIcon","dropText","dropProcessing","dropProcessingSpinner","thumbnail","previewGeneration","cachedThumbnailNotAvailableImg","cachedWaitingForThumbnailImg","isEditElementsExist","isRetryElementExist","templateHtml","showThumbnails","serverScale","cacheThumbnailPlaceholders","notAvailableUrl","waitingUrl","updatedImg","displayWaitingImg","waitingImgPlacement","maybeScalePlaceholderViaCss","show","generateNewPreview","getThumbnail","qqThumbnailId","maybeSetDisplayNotAvailableImg","generateNextQueuedPreview","queuedThumbRequest","update","processUpdateQueuedPreviewRequest","processNewQueuedPreviewRequest","getCancel","getTemplateEl","getContinue","getDialog","getDelete","getDropProcessing","getEditIcon","getPause","getProgress","getRetry","getSpinner","cssClass","previewing","notAvailableImgPlacement","parseAndGetTemplate","scriptEl","scriptHtml","fileListNode","tempTemplateEl","fileListHtml","defaultButton","dropTextEl","uploaderEl","fileTemplate","prependFile","parentEl","beforeEl","optFileOrBlob","relatedThumbnailId","useCachedPreview","showWaitingImg","setProgressBarWidth","percent","bar","progressBarSelector","targetThumbnailId","cachedThumbnailId","targetThumbnail","cachedThumbnail","hideTotalProgress","cantRenderEl","prependInfo","hideForever","batch","fileEl","fileNameEl","thumb","waitingImg","currentNode","getFileList","filenameEl","isFileName","icon","isEditIcon","isEditInput","isCancel","allowContinueButton","isPause","isContinueButton","isDeleteButton","isRetry","textEl","dialog","messageEl","inputEl","cancelBtn","okBtn","closeHandler","cancelClickHandler","okClickHandler","close","showModal","UiEventHandler","s","protectedApi","eventType","attachTo","onHandled","srcElement","getFileIdFromItem","qqFileId","getDisposeSupport","inheritedInternalApi","buttonHandlers","examineEvent","buttonType","firstLetterCapButtonType","handleFilenameEdit","FilenameEditHandler","handleInputFocus","getFilenameSansExtension","filenameSansExt","getOriginalExtension","origName","handleNameUpdate","newFilenameInputEl","origExtension","registerInputBlurHandler","registerInputEnterKeyHandler","keyCode","which","focusInput","focus"],"mappings":"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","file":"fine-uploader.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/* globals qq */\n/**\n * Fine Uploader top-level Error container. Inherits from `Error`.\n */\n(function() {\n \"use strict\";\n\n qq.Error = function(message) {\n this.message = \"[Fine Uploader \" + qq.version + \"] \" + message;\n };\n\n qq.Error.prototype = new Error();\n}());\n","/*global qq */\nqq.version = \"5.13.0\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for Filesystem API support since webkit does not expose the DataTransfer interface\n function isChrome21OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[2][1-9]|Chrome\\/[3-9][0-9]/) !== undefined;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n supportsFolderDrop = supportsFileDrop && isChrome21OrHigher();\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/* globals qq */\n/**\n * Placeholder for a Blob that will be generated on-demand.\n *\n * @param referenceBlob Parent of the generated blob\n * @param onCreate Function to invoke when the blob must be created. Must be promissory.\n * @constructor\n */\nqq.BlobProxy = function(referenceBlob, onCreate) {\n \"use strict\";\n\n qq.extend(this, {\n referenceBlob: referenceBlob,\n\n create: function() {\n return onCreate(referenceBlob);\n }\n });\n};\n","/*globals qq*/\n\n/**\n * This module represents an upload or \"Select File(s)\" button. It's job is to embed an opaque ` `\n * element as a child of a provided \"container\" element. This \"container\" element (`options.element`) is used to provide\n * a custom style for the ` ` element. The ability to change the style of the container element is also\n * provided here by adding CSS classes to the container on hover/focus.\n *\n * TODO Eliminate the mouseover and mouseout event handlers since the :hover CSS pseudo-class should now be\n * available on all supported browsers.\n *\n * @param o Options to override the default values\n */\nqq.UploadButton = function(o) {\n \"use strict\";\n\n var self = this,\n\n disposeSupport = new qq.DisposeSupport(),\n\n options = {\n // Corresponds to the `accept` attribute on the associated ` `\n acceptFiles: null,\n\n // \"Container\" element\n element: null,\n\n focusClass: \"qq-upload-button-focus\",\n\n // A true value allows folders to be selected, if supported by the UA\n folders: false,\n\n // **This option will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n hoverClass: \"qq-upload-button-hover\",\n\n ios8BrowserCrashWorkaround: false,\n\n // If true adds `multiple` attribute to ` `\n multiple: false,\n\n // `name` attribute of ` `\n name: \"qqfile\",\n\n // Called when the browser invokes the onchange handler on the ` `\n onChange: function(input) {},\n\n title: null\n },\n input, buttonId;\n\n // Overrides any of the default option values with any option values passed in during construction.\n qq.extend(options, o);\n\n buttonId = qq.getUniqueId();\n\n // Embed an opaque ` ` element as a child of `options.element`.\n function createInput() {\n var input = document.createElement(\"input\");\n\n input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId);\n input.setAttribute(\"title\", options.title);\n\n self.setMultiple(options.multiple, input);\n\n if (options.folders && qq.supportedFeatures.folderSelection) {\n // selecting directories is only possible in Chrome now, via a vendor-specific prefixed attribute\n input.setAttribute(\"webkitdirectory\", \"\");\n }\n\n if (options.acceptFiles) {\n input.setAttribute(\"accept\", options.acceptFiles);\n }\n\n input.setAttribute(\"type\", \"file\");\n input.setAttribute(\"name\", options.name);\n\n qq(input).css({\n position: \"absolute\",\n // in Opera only 'browse' button\n // is clickable and it is located at\n // the right side of the input\n right: 0,\n top: 0,\n fontFamily: \"Arial\",\n // It's especially important to make this an arbitrarily large value\n // to ensure the rendered input button in IE takes up the entire\n // space of the container element. Otherwise, the left side of the\n // button will require a double-click to invoke the file chooser.\n // In other browsers, this might cause other issues, so a large font-size\n // is only used in IE. There is a bug in IE8 where the opacity style is ignored\n // in some cases when the font-size is large. So, this workaround is not applied\n // to IE8.\n fontSize: qq.ie() && !qq.ie8() ? \"3500px\" : \"118px\",\n margin: 0,\n padding: 0,\n cursor: \"pointer\",\n opacity: 0\n });\n\n // Setting the file input's height to 100% in IE7 causes\n // most of the visible button to be unclickable.\n !qq.ie7() && qq(input).css({height: \"100%\"});\n\n options.element.appendChild(input);\n\n disposeSupport.attach(input, \"change\", function() {\n options.onChange(input);\n });\n\n // **These event handlers will be removed** in the future as the :hover CSS pseudo-class is available on all supported browsers\n disposeSupport.attach(input, \"mouseover\", function() {\n qq(options.element).addClass(options.hoverClass);\n });\n disposeSupport.attach(input, \"mouseout\", function() {\n qq(options.element).removeClass(options.hoverClass);\n });\n\n disposeSupport.attach(input, \"focus\", function() {\n qq(options.element).addClass(options.focusClass);\n });\n disposeSupport.attach(input, \"blur\", function() {\n qq(options.element).removeClass(options.focusClass);\n });\n\n return input;\n }\n\n // Make button suitable container for input\n qq(options.element).css({\n position: \"relative\",\n overflow: \"hidden\",\n // Make sure browse button is in the right side in Internet Explorer\n direction: \"ltr\"\n });\n\n // Exposed API\n qq.extend(this, {\n getInput: function() {\n return input;\n },\n\n getButtonId: function() {\n return buttonId;\n },\n\n setMultiple: function(isMultiple, optInput) {\n var input = optInput || this.getInput();\n\n // Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash\n // before the file chooser appears if the file input doesn't contain a multiple attribute.\n // See #1283.\n if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {\n input.setAttribute(\"multiple\", \"\");\n }\n\n else {\n if (isMultiple) {\n input.setAttribute(\"multiple\", \"\");\n }\n else {\n input.removeAttribute(\"multiple\");\n }\n }\n },\n\n setAcceptFiles: function(acceptFiles) {\n if (acceptFiles !== options.acceptFiles) {\n input.setAttribute(\"accept\", acceptFiles);\n }\n },\n\n reset: function() {\n if (input.parentNode) {\n qq(input).remove();\n }\n\n qq(options.element).removeClass(options.focusClass);\n input = null;\n input = createInput();\n }\n });\n\n input = createInput();\n};\n\nqq.UploadButton.BUTTON_ID_ATTR_NAME = \"qq-button-id\";\n","/*globals qq */\nqq.UploadData = function(uploaderProxy) {\n \"use strict\";\n\n var data = [],\n byUuid = {},\n byStatus = {},\n byProxyGroupId = {},\n byBatchId = {};\n\n function getDataByIds(idOrIds) {\n if (qq.isArray(idOrIds)) {\n var entries = [];\n\n qq.each(idOrIds, function(idx, id) {\n entries.push(data[id]);\n });\n\n return entries;\n }\n\n return data[idOrIds];\n }\n\n function getDataByUuids(uuids) {\n if (qq.isArray(uuids)) {\n var entries = [];\n\n qq.each(uuids, function(idx, uuid) {\n entries.push(data[byUuid[uuid]]);\n });\n\n return entries;\n }\n\n return data[byUuid[uuids]];\n }\n\n function getDataByStatus(status) {\n var statusResults = [],\n statuses = [].concat(status);\n\n qq.each(statuses, function(index, statusEnum) {\n var statusResultIndexes = byStatus[statusEnum];\n\n if (statusResultIndexes !== undefined) {\n qq.each(statusResultIndexes, function(i, dataIndex) {\n statusResults.push(data[dataIndex]);\n });\n }\n });\n\n return statusResults;\n }\n\n qq.extend(this, {\n /**\n * Adds a new file to the data cache for tracking purposes.\n *\n * @param spec Data that describes this file. Possible properties are:\n *\n * - uuid: Initial UUID for this file.\n * - name: Initial name of this file.\n * - size: Size of this file, omit if this cannot be determined\n * - status: Initial `qq.status` for this file. Omit for `qq.status.SUBMITTING`.\n * - batchId: ID of the batch this file belongs to\n * - proxyGroupId: ID of the proxy group associated with this file\n *\n * @returns {number} Internal ID for this file.\n */\n addFile: function(spec) {\n var status = spec.status || qq.status.SUBMITTING,\n id = data.push({\n name: spec.name,\n originalName: spec.name,\n uuid: spec.uuid,\n size: spec.size == null ? -1 : spec.size,\n status: status\n }) - 1;\n\n if (spec.batchId) {\n data[id].batchId = spec.batchId;\n\n if (byBatchId[spec.batchId] === undefined) {\n byBatchId[spec.batchId] = [];\n }\n byBatchId[spec.batchId].push(id);\n }\n\n if (spec.proxyGroupId) {\n data[id].proxyGroupId = spec.proxyGroupId;\n\n if (byProxyGroupId[spec.proxyGroupId] === undefined) {\n byProxyGroupId[spec.proxyGroupId] = [];\n }\n byProxyGroupId[spec.proxyGroupId].push(id);\n }\n\n data[id].id = id;\n byUuid[spec.uuid] = id;\n\n if (byStatus[status] === undefined) {\n byStatus[status] = [];\n }\n byStatus[status].push(id);\n\n uploaderProxy.onStatusChange(id, null, status);\n\n return id;\n },\n\n retrieve: function(optionalFilter) {\n if (qq.isObject(optionalFilter) && data.length) {\n if (optionalFilter.id !== undefined) {\n return getDataByIds(optionalFilter.id);\n }\n\n else if (optionalFilter.uuid !== undefined) {\n return getDataByUuids(optionalFilter.uuid);\n }\n\n else if (optionalFilter.status) {\n return getDataByStatus(optionalFilter.status);\n }\n }\n else {\n return qq.extend([], data, true);\n }\n },\n\n reset: function() {\n data = [];\n byUuid = {};\n byStatus = {};\n byBatchId = {};\n },\n\n setStatus: function(id, newStatus) {\n var oldStatus = data[id].status,\n byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id);\n\n byStatus[oldStatus].splice(byStatusOldStatusIndex, 1);\n\n data[id].status = newStatus;\n\n if (byStatus[newStatus] === undefined) {\n byStatus[newStatus] = [];\n }\n byStatus[newStatus].push(id);\n\n uploaderProxy.onStatusChange(id, oldStatus, newStatus);\n },\n\n uuidChanged: function(id, newUuid) {\n var oldUuid = data[id].uuid;\n\n data[id].uuid = newUuid;\n byUuid[newUuid] = id;\n delete byUuid[oldUuid];\n },\n\n updateName: function(id, newName) {\n data[id].name = newName;\n },\n\n updateSize: function(id, newSize) {\n data[id].size = newSize;\n },\n\n // Only applicable if this file has a parent that we may want to reference later.\n setParentId: function(targetId, parentId) {\n data[targetId].parentId = parentId;\n },\n\n getIdsInProxyGroup: function(id) {\n var proxyGroupId = data[id].proxyGroupId;\n\n if (proxyGroupId) {\n return byProxyGroupId[proxyGroupId];\n }\n return [];\n },\n\n getIdsInBatch: function(id) {\n var batchId = data[id].batchId;\n\n return byBatchId[batchId];\n }\n });\n};\n\nqq.status = {\n SUBMITTING: \"submitting\",\n SUBMITTED: \"submitted\",\n REJECTED: \"rejected\",\n QUEUED: \"queued\",\n CANCELED: \"canceled\",\n PAUSED: \"paused\",\n UPLOADING: \"uploading\",\n UPLOAD_RETRYING: \"retrying upload\",\n UPLOAD_SUCCESSFUL: \"upload successful\",\n UPLOAD_FAILED: \"upload failed\",\n DELETE_FAILED: \"delete failed\",\n DELETING: \"deleting\",\n DELETED: \"deleted\"\n};\n","/*globals qq*/\n/**\n * Defines the public API for FineUploaderBasic mode.\n */\n(function() {\n \"use strict\";\n\n qq.basePublicApi = {\n // DEPRECATED - TODO REMOVE IN NEXT MAJOR RELEASE (replaced by addFiles)\n addBlobs: function(blobDataOrArray, params, endpoint) {\n this.addFiles(blobDataOrArray, params, endpoint);\n },\n\n addInitialFiles: function(cannedFileList) {\n var self = this;\n\n qq.each(cannedFileList, function(index, cannedFile) {\n self._addCannedFile(cannedFile);\n });\n },\n\n addFiles: function(data, params, endpoint) {\n this._maybeHandleIos8SafariWorkaround();\n\n var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId,\n\n processBlob = qq.bind(function(blob) {\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName\n }, batchId, verifiedFiles);\n }, this),\n\n processBlobData = qq.bind(function(blobData) {\n this._handleNewFile(blobData, batchId, verifiedFiles);\n }, this),\n\n processCanvas = qq.bind(function(canvas) {\n var blob = qq.canvasToBlob(canvas);\n\n this._handleNewFile({\n blob: blob,\n name: this._options.blobs.defaultName + \".png\"\n }, batchId, verifiedFiles);\n }, this),\n\n processCanvasData = qq.bind(function(canvasData) {\n var normalizedQuality = canvasData.quality && canvasData.quality / 100,\n blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality);\n\n this._handleNewFile({\n blob: blob,\n name: canvasData.name\n }, batchId, verifiedFiles);\n }, this),\n\n processFileOrInput = qq.bind(function(fileOrInput) {\n if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) {\n var files = Array.prototype.slice.call(fileOrInput.files),\n self = this;\n\n qq.each(files, function(idx, file) {\n self._handleNewFile(file, batchId, verifiedFiles);\n });\n }\n else {\n this._handleNewFile(fileOrInput, batchId, verifiedFiles);\n }\n }, this),\n\n normalizeData = function() {\n if (qq.isFileList(data)) {\n data = Array.prototype.slice.call(data);\n }\n data = [].concat(data);\n },\n\n self = this,\n verifiedFiles = [];\n\n this._currentBatchId = batchId;\n\n if (data) {\n normalizeData();\n\n qq.each(data, function(idx, fileContainer) {\n if (qq.isFileOrInput(fileContainer)) {\n processFileOrInput(fileContainer);\n }\n else if (qq.isBlob(fileContainer)) {\n processBlob(fileContainer);\n }\n else if (qq.isObject(fileContainer)) {\n if (fileContainer.blob && fileContainer.name) {\n processBlobData(fileContainer);\n }\n else if (fileContainer.canvas && fileContainer.name) {\n processCanvasData(fileContainer);\n }\n }\n else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === \"canvas\") {\n processCanvas(fileContainer);\n }\n else {\n self.log(fileContainer + \" is not a valid file container! Ignoring!\", \"warn\");\n }\n });\n\n this.log(\"Received \" + verifiedFiles.length + \" files.\");\n this._prepareItemsForUpload(verifiedFiles, params, endpoint);\n }\n },\n\n cancel: function(id) {\n this._handler.cancel(id);\n },\n\n cancelAll: function() {\n var storedIdsCopy = [],\n self = this;\n\n qq.extend(storedIdsCopy, this._storedIds);\n qq.each(storedIdsCopy, function(idx, storedFileId) {\n self.cancel(storedFileId);\n });\n\n this._handler.cancelAll();\n },\n\n clearStoredFiles: function() {\n this._storedIds = [];\n },\n\n continueUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n if (uploadData.status === qq.status.PAUSED) {\n this.log(qq.format(\"Paused file ID {} ({}) will be continued. Not paused.\", id, this.getName(id)));\n this._uploadFile(id);\n return true;\n }\n else {\n this.log(qq.format(\"Ignoring continue for file ID {} ({}). Not paused.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n deleteFile: function(id) {\n return this._onSubmitDelete(id);\n },\n\n // TODO document?\n doesExist: function(fileOrBlobId) {\n return this._handler.isValid(fileOrBlobId);\n },\n\n // Generate a variable size thumbnail on an img or canvas,\n // returning a promise that is fulfilled when the attempt completes.\n // Thumbnail can either be based off of a URL for an image returned\n // by the server in the upload response, or the associated `Blob`.\n drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {\n var promiseToReturn = new qq.Promise(),\n fileOrUrl, options;\n\n if (this._imageGenerator) {\n fileOrUrl = this._thumbnailUrls[fileId];\n options = {\n customResizeFunction: customResizeFunction,\n maxSize: maxSize > 0 ? maxSize : null,\n scale: maxSize > 0\n };\n\n // If client-side preview generation is possible\n // and we are not specifically looking for the image URl returned by the server...\n if (!fromServer && qq.supportedFeatures.imagePreviews) {\n fileOrUrl = this.getFile(fileId);\n }\n\n /* jshint eqeqeq:false,eqnull:true */\n if (fileOrUrl == null) {\n promiseToReturn.failure({container: imgOrCanvas, error: \"File or URL not found.\"});\n }\n else {\n this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(\n function success(modifiedContainer) {\n promiseToReturn.success(modifiedContainer);\n },\n\n function failure(container, reason) {\n promiseToReturn.failure({container: container, error: reason || \"Problem generating thumbnail\"});\n }\n );\n }\n }\n else {\n promiseToReturn.failure({container: imgOrCanvas, error: \"Missing image generator module\"});\n }\n\n return promiseToReturn;\n },\n\n getButton: function(fileId) {\n return this._getButton(this._buttonIdsForFileIds[fileId]);\n },\n\n getEndpoint: function(fileId) {\n return this._endpointStore.get(fileId);\n },\n\n getFile: function(fileOrBlobId) {\n return this._handler.getFile(fileOrBlobId) || null;\n },\n\n getInProgress: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED\n ]\n }).length;\n },\n\n getName: function(id) {\n return this._uploadData.retrieve({id: id}).name;\n },\n\n // Parent ID for a specific file, or null if this is the parent, or if it has no parent.\n getParentId: function(id) {\n var uploadDataEntry = this.getUploads({id: id}),\n parentId = null;\n\n if (uploadDataEntry) {\n if (uploadDataEntry.parentId !== undefined) {\n parentId = uploadDataEntry.parentId;\n }\n }\n\n return parentId;\n },\n\n getResumableFilesData: function() {\n return this._handler.getResumableFilesData();\n },\n\n getSize: function(id) {\n return this._uploadData.retrieve({id: id}).size;\n },\n\n getNetUploads: function() {\n return this._netUploaded;\n },\n\n getRemainingAllowedItems: function() {\n var allowedItems = this._currentItemLimit;\n\n if (allowedItems > 0) {\n return allowedItems - this._netUploadedOrQueued;\n }\n\n return null;\n },\n\n getUploads: function(optionalFilter) {\n return this._uploadData.retrieve(optionalFilter);\n },\n\n getUuid: function(id) {\n return this._uploadData.retrieve({id: id}).uuid;\n },\n\n log: function(str, level) {\n if (this._options.debug && (!level || level === \"info\")) {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str);\n }\n else if (level && level !== \"info\") {\n qq.log(\"[Fine Uploader \" + qq.version + \"] \" + str, level);\n\n }\n },\n\n pauseUpload: function(id) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) {\n return false;\n }\n\n // Pause only really makes sense if the file is uploading or retrying\n if (qq.indexOf([qq.status.UPLOADING, qq.status.UPLOAD_RETRYING], uploadData.status) >= 0) {\n if (this._handler.pause(id)) {\n this._uploadData.setStatus(id, qq.status.PAUSED);\n return true;\n }\n else {\n this.log(qq.format(\"Unable to pause file ID {} ({}).\", id, this.getName(id)), \"error\");\n }\n }\n else {\n this.log(qq.format(\"Ignoring pause for file ID {} ({}). Not in progress.\", id, this.getName(id)), \"error\");\n }\n\n return false;\n },\n\n reset: function() {\n this.log(\"Resetting uploader...\");\n\n this._handler.reset();\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n\n this._paramsStore.reset();\n this._endpointStore.reset();\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData.reset();\n this._buttonIdsForFileIds = [];\n\n this._pasteHandler && this._pasteHandler.reset();\n this._options.session.refreshOnReset && this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._totalProgress && this._totalProgress.reset();\n },\n\n retry: function(id) {\n return this._manualRetry(id);\n },\n\n scaleImage: function(id, specs) {\n var self = this;\n\n return qq.Scaler.prototype.scaleImage(id, specs, {\n log: qq.bind(self.log, self),\n getFile: qq.bind(self.getFile, self),\n uploadData: self._uploadData\n });\n },\n\n setCustomHeaders: function(headers, id) {\n this._customHeadersStore.set(headers, id);\n },\n\n setDeleteFileCustomHeaders: function(headers, id) {\n this._deleteFileCustomHeadersStore.set(headers, id);\n },\n\n setDeleteFileEndpoint: function(endpoint, id) {\n this._deleteFileEndpointStore.set(endpoint, id);\n },\n\n setDeleteFileParams: function(params, id) {\n this._deleteFileParamsStore.set(params, id);\n },\n\n // Re-sets the default endpoint, an endpoint for a specific file, or an endpoint for a specific button\n setEndpoint: function(endpoint, id) {\n this._endpointStore.set(endpoint, id);\n },\n\n setForm: function(elementOrId) {\n this._updateFormSupportAndParams(elementOrId);\n },\n\n setItemLimit: function(newItemLimit) {\n this._currentItemLimit = newItemLimit;\n },\n\n setName: function(id, newName) {\n this._uploadData.updateName(id, newName);\n },\n\n setParams: function(params, id) {\n this._paramsStore.set(params, id);\n },\n\n setUuid: function(id, newUuid) {\n return this._uploadData.uuidChanged(id, newUuid);\n },\n\n uploadStoredFiles: function() {\n if (this._storedIds.length === 0) {\n this._itemError(\"noFilesError\");\n }\n else {\n this._uploadStoredFiles();\n }\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploaderBasic mode.\n */\n qq.basePrivateApi = {\n // Updates internal state with a file record (not backed by a live file). Returns the assigned ID.\n _addCannedFile: function(sessionData) {\n var id = this._uploadData.addFile({\n uuid: sessionData.uuid,\n name: sessionData.name,\n size: sessionData.size,\n status: qq.status.UPLOAD_SUCCESSFUL\n });\n\n sessionData.deleteFileEndpoint && this.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id);\n sessionData.deleteFileParams && this.setDeleteFileParams(sessionData.deleteFileParams, id);\n\n if (sessionData.thumbnailUrl) {\n this._thumbnailUrls[id] = sessionData.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._netUploadedOrQueued++;\n\n return id;\n },\n\n _annotateWithButtonId: function(file, associatedInput) {\n if (qq.isFile(file)) {\n file.qqButtonId = this._getButtonId(associatedInput);\n }\n },\n\n _batchError: function(message) {\n this._options.callbacks.onError(null, null, message, undefined);\n },\n\n _createDeleteHandler: function() {\n var self = this;\n\n return new qq.DeleteFileAjaxRequester({\n method: this._options.deleteFile.method.toUpperCase(),\n maxConnections: this._options.maxConnections,\n uuidParamName: this._options.request.uuidName,\n customHeaders: this._deleteFileCustomHeadersStore,\n paramsStore: this._deleteFileParamsStore,\n endpointStore: this._deleteFileEndpointStore,\n cors: this._options.cors,\n log: qq.bind(self.log, self),\n onDelete: function(id) {\n self._onDelete(id);\n self._options.callbacks.onDelete(id);\n },\n onDeleteComplete: function(id, xhrOrXdr, isError) {\n self._onDeleteComplete(id, xhrOrXdr, isError);\n self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError);\n }\n\n });\n },\n\n _createPasteHandler: function() {\n var self = this;\n\n return new qq.PasteSupport({\n targetElement: this._options.paste.targetElement,\n callbacks: {\n log: qq.bind(self.log, self),\n pasteReceived: function(blob) {\n self._handleCheckedCallback({\n name: \"onPasteReceived\",\n callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob),\n onSuccess: qq.bind(self._handlePasteSuccess, self, blob),\n identifier: \"pasted image\"\n });\n }\n }\n });\n },\n\n _createStore: function(initialValue, _readOnlyValues_) {\n var store = {},\n catchall = initialValue,\n perIdReadOnlyValues = {},\n readOnlyValues = _readOnlyValues_,\n copy = function(orig) {\n if (qq.isObject(orig)) {\n return qq.extend({}, orig);\n }\n return orig;\n },\n getReadOnlyValues = function() {\n if (qq.isFunction(readOnlyValues)) {\n return readOnlyValues();\n }\n return readOnlyValues;\n },\n includeReadOnlyValues = function(id, existing) {\n if (readOnlyValues && qq.isObject(existing)) {\n qq.extend(existing, getReadOnlyValues());\n }\n\n if (perIdReadOnlyValues[id]) {\n qq.extend(existing, perIdReadOnlyValues[id]);\n }\n };\n\n return {\n set: function(val, id) {\n /*jshint eqeqeq: true, eqnull: true*/\n if (id == null) {\n store = {};\n catchall = copy(val);\n }\n else {\n store[id] = copy(val);\n }\n },\n\n get: function(id) {\n var values;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (id != null && store[id]) {\n values = store[id];\n }\n else {\n values = copy(catchall);\n }\n\n includeReadOnlyValues(id, values);\n\n return copy(values);\n },\n\n addReadOnly: function(id, values) {\n // Only applicable to Object stores\n if (qq.isObject(store)) {\n // If null ID, apply readonly values to all files\n if (id === null) {\n if (qq.isFunction(values)) {\n readOnlyValues = values;\n }\n else {\n readOnlyValues = readOnlyValues || {};\n qq.extend(readOnlyValues, values);\n }\n }\n else {\n perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};\n qq.extend(perIdReadOnlyValues[id], values);\n }\n }\n },\n\n remove: function(fileId) {\n return delete store[fileId];\n },\n\n reset: function() {\n store = {};\n perIdReadOnlyValues = {};\n catchall = initialValue;\n }\n };\n },\n\n _createUploadDataTracker: function() {\n var self = this;\n\n return new qq.UploadData({\n getName: function(id) {\n return self.getName(id);\n },\n getUuid: function(id) {\n return self.getUuid(id);\n },\n getSize: function(id) {\n return self.getSize(id);\n },\n onStatusChange: function(id, oldStatus, newStatus) {\n self._onUploadStatusChange(id, oldStatus, newStatus);\n self._options.callbacks.onStatusChange(id, oldStatus, newStatus);\n self._maybeAllComplete(id, newStatus);\n\n if (self._totalProgress) {\n setTimeout(function() {\n self._totalProgress.onStatusChange(id, oldStatus, newStatus);\n }, 0);\n }\n }\n });\n },\n\n /**\n * Generate a tracked upload button.\n *\n * @param spec Object containing a required `element` property\n * along with optional `multiple`, `accept`, and `folders`.\n * @returns {qq.UploadButton}\n * @private\n */\n _createUploadButton: function(spec) {\n var self = this,\n acceptFiles = spec.accept || this._options.validation.acceptFiles,\n allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions,\n button;\n\n function allowMultiple() {\n if (qq.supportedFeatures.ajaxUploading) {\n // Workaround for bug in iOS7+ (see #1039)\n if (self._options.workarounds.iosEmptyVideos &&\n qq.ios() &&\n !qq.ios6() &&\n self._isAllowedExtension(allowedExtensions, \".mov\")) {\n\n return false;\n }\n\n if (spec.multiple === undefined) {\n return self._options.multiple;\n }\n\n return spec.multiple;\n }\n\n return false;\n }\n\n button = new qq.UploadButton({\n acceptFiles: acceptFiles,\n element: spec.element,\n focusClass: this._options.classes.buttonFocus,\n folders: spec.folders,\n hoverClass: this._options.classes.buttonHover,\n ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash,\n multiple: allowMultiple(),\n name: this._options.request.inputName,\n onChange: function(input) {\n self._onInputChange(input);\n },\n title: spec.title == null ? this._options.text.fileInputTitle : spec.title\n });\n\n this._disposeSupport.addDisposer(function() {\n button.dispose();\n });\n\n self._buttons.push(button);\n\n return button;\n },\n\n _createUploadHandler: function(additionalOptions, namespace) {\n var self = this,\n lastOnProgress = {},\n options = {\n debug: this._options.debug,\n maxConnections: this._options.maxConnections,\n cors: this._options.cors,\n paramsStore: this._paramsStore,\n endpointStore: this._endpointStore,\n chunking: this._options.chunking,\n resume: this._options.resume,\n blobs: this._options.blobs,\n log: qq.bind(self.log, self),\n preventRetryParam: this._options.retry.preventRetryResponseProperty,\n onProgress: function(id, name, loaded, total) {\n if (loaded < 0 || total < 0) {\n return;\n }\n\n if (lastOnProgress[id]) {\n if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n }\n else {\n self._onProgress(id, name, loaded, total);\n self._options.callbacks.onProgress(id, name, loaded, total);\n }\n\n lastOnProgress[id] = {loaded: loaded, total: total};\n\n },\n onComplete: function(id, name, result, xhr) {\n delete lastOnProgress[id];\n\n var status = self.getUploads({id: id}).status,\n retVal;\n\n // This is to deal with some observed cases where the XHR readyStateChange handler is\n // invoked by the browser multiple times for the same XHR instance with the same state\n // readyState value. Higher level: don't invoke complete-related code if we've already\n // done this.\n if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) {\n return;\n }\n\n retVal = self._onComplete(id, name, result, xhr);\n\n // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback\n // until the promise has been fulfilled.\n if (retVal instanceof qq.Promise) {\n retVal.done(function() {\n self._options.callbacks.onComplete(id, name, result, xhr);\n });\n }\n else {\n self._options.callbacks.onComplete(id, name, result, xhr);\n }\n },\n onCancel: function(id, name, cancelFinalizationEffort) {\n var promise = new qq.Promise();\n\n self._handleCheckedCallback({\n name: \"onCancel\",\n callback: qq.bind(self._options.callbacks.onCancel, self, id, name),\n onFailure: promise.failure,\n onSuccess: function() {\n cancelFinalizationEffort.then(function() {\n self._onCancel(id, name);\n });\n\n promise.success();\n },\n identifier: id\n });\n\n return promise;\n },\n onUploadPrep: qq.bind(this._onUploadPrep, this),\n onUpload: function(id, name) {\n self._onUpload(id, name);\n self._options.callbacks.onUpload(id, name);\n },\n onUploadChunk: function(id, name, chunkData) {\n self._onUploadChunk(id, chunkData);\n self._options.callbacks.onUploadChunk(id, name, chunkData);\n },\n onUploadChunkSuccess: function(id, chunkData, result, xhr) {\n self._options.callbacks.onUploadChunkSuccess.apply(self, arguments);\n },\n onResume: function(id, name, chunkData) {\n return self._options.callbacks.onResume(id, name, chunkData);\n },\n onAutoRetry: function(id, name, responseJSON, xhr) {\n return self._onAutoRetry.apply(self, arguments);\n },\n onUuidChanged: function(id, newUuid) {\n self.log(\"Server requested UUID change from '\" + self.getUuid(id) + \"' to '\" + newUuid + \"'\");\n self.setUuid(id, newUuid);\n },\n getName: qq.bind(self.getName, self),\n getUuid: qq.bind(self.getUuid, self),\n getSize: qq.bind(self.getSize, self),\n setSize: qq.bind(self._setSize, self),\n getDataByUuid: function(uuid) {\n return self.getUploads({uuid: uuid});\n },\n isQueued: function(id) {\n var status = self.getUploads({id: id}).status;\n return status === qq.status.QUEUED ||\n status === qq.status.SUBMITTED ||\n status === qq.status.UPLOAD_RETRYING ||\n status === qq.status.PAUSED;\n },\n getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup,\n getIdsInBatch: self._uploadData.getIdsInBatch\n };\n\n qq.each(this._options.request, function(prop, val) {\n options[prop] = val;\n });\n\n options.customHeaders = this._customHeadersStore;\n\n if (additionalOptions) {\n qq.each(additionalOptions, function(key, val) {\n options[key] = val;\n });\n }\n\n return new qq.UploadHandlerController(options, namespace);\n },\n\n _fileOrBlobRejected: function(id) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.REJECTED);\n },\n\n _formatSize: function(bytes) {\n if (bytes === 0) {\n return bytes + this._options.text.sizeSymbols[0];\n }\n var i = -1;\n do {\n bytes = bytes / 1000;\n i++;\n } while (bytes > 999);\n\n return Math.max(bytes, 0.1).toFixed(1) + this._options.text.sizeSymbols[i];\n },\n\n // Creates an internal object that tracks various properties of each extra button,\n // and then actually creates the extra button.\n _generateExtraButtonSpecs: function() {\n var self = this;\n\n this._extraButtonSpecs = {};\n\n qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) {\n var multiple = extraButtonOptionEntry.multiple,\n validation = qq.extend({}, self._options.validation, true),\n extraButtonSpec = qq.extend({}, extraButtonOptionEntry);\n\n if (multiple === undefined) {\n multiple = self._options.multiple;\n }\n\n if (extraButtonSpec.validation) {\n qq.extend(validation, extraButtonOptionEntry.validation, true);\n }\n\n qq.extend(extraButtonSpec, {\n multiple: multiple,\n validation: validation\n }, true);\n\n self._initExtraButton(extraButtonSpec);\n });\n },\n\n _getButton: function(buttonId) {\n var extraButtonsSpec = this._extraButtonSpecs[buttonId];\n\n if (extraButtonsSpec) {\n return extraButtonsSpec.element;\n }\n else if (buttonId === this._defaultButtonId) {\n return this._options.button;\n }\n },\n\n /**\n * Gets the internally used tracking ID for a button.\n *\n * @param buttonOrFileInputOrFile `File`, ` `, or a button container element\n * @returns {*} The button's ID, or undefined if no ID is recoverable\n * @private\n */\n _getButtonId: function(buttonOrFileInputOrFile) {\n var inputs, fileInput,\n fileBlobOrInput = buttonOrFileInputOrFile;\n\n // We want the reference file/blob here if this is a proxy (a file that will be generated on-demand later)\n if (fileBlobOrInput instanceof qq.BlobProxy) {\n fileBlobOrInput = fileBlobOrInput.referenceBlob;\n }\n\n // If the item is a `Blob` it will never be associated with a button or drop zone.\n if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) {\n if (qq.isFile(fileBlobOrInput)) {\n return fileBlobOrInput.qqButtonId;\n }\n else if (fileBlobOrInput.tagName.toLowerCase() === \"input\" &&\n fileBlobOrInput.type.toLowerCase() === \"file\") {\n\n return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n\n inputs = fileBlobOrInput.getElementsByTagName(\"input\");\n\n qq.each(inputs, function(idx, input) {\n if (input.getAttribute(\"type\") === \"file\") {\n fileInput = input;\n return false;\n }\n });\n\n if (fileInput) {\n return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME);\n }\n }\n },\n\n _getNotFinished: function() {\n return this._uploadData.retrieve({\n status: [\n qq.status.UPLOADING,\n qq.status.UPLOAD_RETRYING,\n qq.status.QUEUED,\n qq.status.SUBMITTING,\n qq.status.SUBMITTED,\n qq.status.PAUSED\n ]\n }).length;\n },\n\n // Get the validation options for this button. Could be the default validation option\n // or a specific one assigned to this particular button.\n _getValidationBase: function(buttonId) {\n var extraButtonSpec = this._extraButtonSpecs[buttonId];\n\n return extraButtonSpec ? extraButtonSpec.validation : this._options.validation;\n },\n\n _getValidationDescriptor: function(fileWrapper) {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return {\n name: qq.getFilename(fileWrapper.file.referenceBlob),\n size: fileWrapper.file.referenceBlob.size\n };\n }\n\n return {\n name: this.getUploads({id: fileWrapper.id}).name,\n size: this.getUploads({id: fileWrapper.id}).size\n };\n },\n\n _getValidationDescriptors: function(fileWrappers) {\n var self = this,\n fileDescriptors = [];\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n fileDescriptors.push(self._getValidationDescriptor(fileWrapper));\n });\n\n return fileDescriptors;\n },\n\n // Allows camera access on either the default or an extra button for iOS devices.\n _handleCameraAccess: function() {\n if (this._options.camera.ios && qq.ios()) {\n var acceptIosCamera = \"image/*;capture=camera\",\n button = this._options.camera.button,\n buttonId = button ? this._getButtonId(button) : this._defaultButtonId,\n optionRoot = this._options;\n\n // If we are not targeting the default button, it is an \"extra\" button\n if (buttonId && buttonId !== this._defaultButtonId) {\n optionRoot = this._extraButtonSpecs[buttonId];\n }\n\n // Camera access won't work in iOS if the `multiple` attribute is present on the file input\n optionRoot.multiple = false;\n\n // update the options\n if (optionRoot.validation.acceptFiles === null) {\n optionRoot.validation.acceptFiles = acceptIosCamera;\n }\n else {\n optionRoot.validation.acceptFiles += \",\" + acceptIosCamera;\n }\n\n // update the already-created button\n qq.each(this._buttons, function(idx, button) {\n if (button.getButtonId() === buttonId) {\n button.setMultiple(optionRoot.multiple);\n button.setAcceptFiles(optionRoot.acceptFiles);\n\n return false;\n }\n });\n }\n },\n\n _handleCheckedCallback: function(details) {\n var self = this,\n callbackRetVal = details.callback();\n\n if (qq.isGenericPromise(callbackRetVal)) {\n this.log(details.name + \" - waiting for \" + details.name + \" promise to be fulfilled for \" + details.identifier);\n return callbackRetVal.then(\n function(successParam) {\n self.log(details.name + \" promise success for \" + details.identifier);\n details.onSuccess(successParam);\n },\n function() {\n if (details.onFailure) {\n self.log(details.name + \" promise failure for \" + details.identifier);\n details.onFailure();\n }\n else {\n self.log(details.name + \" promise failure for \" + details.identifier);\n }\n });\n }\n\n if (callbackRetVal !== false) {\n details.onSuccess(callbackRetVal);\n }\n else {\n if (details.onFailure) {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Invoking failure callback.\");\n details.onFailure();\n }\n else {\n this.log(details.name + \" - return value was 'false' for \" + details.identifier + \". Will not proceed.\");\n }\n }\n\n return callbackRetVal;\n },\n\n // Updates internal state when a new file has been received, and adds it along with its ID to a passed array.\n _handleNewFile: function(file, batchId, newFileWrapperList) {\n var self = this,\n uuid = qq.getUniqueId(),\n size = -1,\n name = qq.getFilename(file),\n actualFile = file.blob || file,\n handler = this._customNewFileHandler ?\n this._customNewFileHandler :\n qq.bind(self._handleNewFileGeneric, self);\n\n if (!qq.isInput(actualFile) && actualFile.size >= 0) {\n size = actualFile.size;\n }\n\n handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, {\n uploadData: self._uploadData,\n paramsStore: self._paramsStore,\n addFileToHandler: function(id, file) {\n self._handler.add(id, file);\n self._netUploadedOrQueued++;\n self._trackButton(id);\n }\n });\n },\n\n _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) {\n var id = this._uploadData.addFile({uuid: uuid, name: name, size: size, batchId: batchId});\n\n this._handler.add(id, file);\n this._trackButton(id);\n\n this._netUploadedOrQueued++;\n\n fileList.push({id: id, file: file});\n },\n\n _handlePasteSuccess: function(blob, extSuppliedName) {\n var extension = blob.type.split(\"/\")[1],\n name = extSuppliedName;\n\n /*jshint eqeqeq: true, eqnull: true*/\n if (name == null) {\n name = this._options.paste.defaultName;\n }\n\n name += \".\" + extension;\n\n this.addFiles({\n name: name,\n blob: blob\n });\n },\n\n // Creates an extra button element\n _initExtraButton: function(spec) {\n var button = this._createUploadButton({\n accept: spec.validation.acceptFiles,\n allowedExtensions: spec.validation.allowedExtensions,\n element: spec.element,\n folders: spec.folders,\n multiple: spec.multiple,\n title: spec.fileInputTitle\n });\n\n this._extraButtonSpecs[button.getButtonId()] = spec;\n },\n\n _initFormSupportAndParams: function() {\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore = this._createStore(\n this._options.request.params, this._formSupport.getFormInputsAsObject\n );\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this._options.request.endpoint = this._formSupport.newEndpoint;\n }\n }\n else {\n this._paramsStore = this._createStore(this._options.request.params);\n }\n },\n\n _isDeletePossible: function() {\n if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) {\n return false;\n }\n\n if (this._options.cors.expected) {\n if (qq.supportedFeatures.deleteFileCorsXhr) {\n return true;\n }\n\n if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) {\n return true;\n }\n\n return false;\n }\n\n return true;\n },\n\n _isAllowedExtension: function(allowed, fileName) {\n var valid = false;\n\n if (!allowed.length) {\n return true;\n }\n\n qq.each(allowed, function(idx, allowedExt) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExt)) {\n /*jshint eqeqeq: true, eqnull: true*/\n var extRegex = new RegExp(\"\\\\.\" + allowedExt + \"$\", \"i\");\n\n if (fileName.match(extRegex) != null) {\n valid = true;\n return false;\n }\n }\n });\n\n return valid;\n },\n\n /**\n * Constructs and returns a message that describes an item/file error. Also calls `onError` callback.\n *\n * @param code REQUIRED - a code that corresponds to a stock message describing this type of error\n * @param maybeNameOrNames names of the items that have failed, if applicable\n * @param item `File`, `Blob`, or ` `\n * @private\n */\n _itemError: function(code, maybeNameOrNames, item) {\n var message = this._options.messages[code],\n allowedExtensions = [],\n names = [].concat(maybeNameOrNames),\n name = names[0],\n buttonId = this._getButtonId(item),\n validationBase = this._getValidationBase(buttonId),\n extensionsForMessage, placeholderMatch;\n\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) {\n /**\n * If an argument is not a string, ignore it. Added when a possible issue with MooTools hijacking the\n * `allowedExtensions` array was discovered. See case #735 in the issue tracker for more details.\n */\n if (qq.isString(allowedExtension)) {\n allowedExtensions.push(allowedExtension);\n }\n });\n\n extensionsForMessage = allowedExtensions.join(\", \").toLowerCase();\n\n r(\"{file}\", this._options.formatFileName(name));\n r(\"{extensions}\", extensionsForMessage);\n r(\"{sizeLimit}\", this._formatSize(validationBase.sizeLimit));\n r(\"{minSizeLimit}\", this._formatSize(validationBase.minSizeLimit));\n\n placeholderMatch = message.match(/(\\{\\w+\\})/g);\n if (placeholderMatch !== null) {\n qq.each(placeholderMatch, function(idx, placeholder) {\n r(placeholder, names[idx]);\n });\n }\n\n this._options.callbacks.onError(null, name, message, undefined);\n\n return message;\n },\n\n /**\n * Conditionally orders a manual retry of a failed upload.\n *\n * @param id File ID of the failed upload\n * @param callback Optional callback to invoke if a retry is prudent.\n * In lieu of asking the upload handler to retry.\n * @returns {boolean} true if a manual retry will occur\n * @private\n */\n _manualRetry: function(id, callback) {\n if (this._onBeforeManualRetry(id)) {\n this._netUploadedOrQueued++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n\n if (callback) {\n callback(id);\n }\n else {\n this._handler.retry(id);\n }\n\n return true;\n }\n },\n\n _maybeAllComplete: function(id, status) {\n var self = this,\n notFinished = this._getNotFinished();\n\n if (status === qq.status.UPLOAD_SUCCESSFUL) {\n this._succeededSinceLastAllComplete.push(id);\n }\n else if (status === qq.status.UPLOAD_FAILED) {\n this._failedSinceLastAllComplete.push(id);\n }\n\n if (notFinished === 0 &&\n (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) {\n // Attempt to ensure onAllComplete is not invoked before other callbacks, such as onCancel & onComplete\n setTimeout(function() {\n self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete);\n }, 0);\n }\n },\n\n _maybeHandleIos8SafariWorkaround: function() {\n var self = this;\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n setTimeout(function() {\n window.alert(self._options.messages.unsupportedBrowserIos8Safari);\n }, 0);\n throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari);\n }\n },\n\n _maybeParseAndSendUploadError: function(id, name, response, xhr) {\n // Assuming no one will actually set the response code to something other than 200\n // and still set 'success' to true...\n if (!response.success) {\n if (xhr && xhr.status !== 200 && !response.error) {\n this._options.callbacks.onError(id, name, \"XHR returned response code \" + xhr.status, xhr);\n }\n else {\n var errorReason = response.error ? response.error : this._options.text.defaultResponseError;\n this._options.callbacks.onError(id, name, errorReason, xhr);\n }\n }\n },\n\n _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) {\n var self = this;\n\n if (items.length > index) {\n if (validItem || !this._options.validation.stopOnFirstInvalidFile) {\n //use setTimeout to prevent a stack overflow with a large number of files in the batch & non-promissory callbacks\n setTimeout(function() {\n var validationDescriptor = self._getValidationDescriptor(items[index]),\n buttonId = self._getButtonId(items[index].file),\n button = self._getButton(buttonId);\n\n self._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button),\n onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint),\n onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint),\n identifier: \"Item '\" + validationDescriptor.name + \"', size: \" + validationDescriptor.size\n });\n }, 0);\n }\n else if (!validItem) {\n for (; index < items.length; index++) {\n self._fileOrBlobRejected(items[index].id);\n }\n }\n }\n },\n\n _onAllComplete: function(successful, failed) {\n this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries);\n\n this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed));\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n },\n\n /**\n * Attempt to automatically retry a failed upload.\n *\n * @param id The file ID of the failed upload\n * @param name The name of the file associated with the failed upload\n * @param responseJSON Response from the server, parsed into a javascript object\n * @param xhr Ajax transport used to send the failed request\n * @param callback Optional callback to be invoked if a retry is prudent.\n * Invoked in lieu of asking the upload handler to retry.\n * @returns {boolean} true if an auto-retry will occur\n * @private\n */\n _onAutoRetry: function(id, name, responseJSON, xhr, callback) {\n var self = this;\n\n self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty];\n\n if (self._shouldAutoRetry(id, name, responseJSON)) {\n var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1000;\n\n self._maybeParseAndSendUploadError.apply(self, arguments);\n self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]);\n self._onBeforeAutoRetry(id, name);\n\n self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING);\n self._retryTimeouts[id] = setTimeout(function() {\n self.log(\"Starting retry for \" + name + \"...\");\n\n if (callback) {\n callback(id);\n }\n else {\n self._handler.retry(id);\n }\n }, retryWaitPeriod);\n\n return true;\n }\n },\n\n _onBeforeAutoRetry: function(id, name) {\n this.log(\"Waiting \" + this._options.retry.autoAttemptDelay + \" seconds before retrying \" + name + \"...\");\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n var itemLimit = this._currentItemLimit,\n fileName;\n\n if (this._preventRetries[id]) {\n this.log(\"Retries are forbidden for id \" + id, \"warn\");\n return false;\n }\n else if (this._handler.isValid(id)) {\n fileName = this.getName(id);\n\n if (this._options.callbacks.onManualRetry(id, fileName) === false) {\n return false;\n }\n\n if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) {\n this._itemError(\"retryFailTooManyItems\");\n return false;\n }\n\n this.log(\"Retrying upload for '\" + fileName + \"' (id: \" + id + \")...\");\n return true;\n }\n else {\n this.log(\"'\" + id + \"' is not a valid file ID\", \"error\");\n return false;\n }\n },\n\n _onCancel: function(id, name) {\n this._netUploadedOrQueued--;\n\n clearTimeout(this._retryTimeouts[id]);\n\n var storedItemIndex = qq.indexOf(this._storedIds, id);\n if (!this._options.autoUpload && storedItemIndex >= 0) {\n this._storedIds.splice(storedItemIndex, 1);\n }\n\n this._uploadData.setStatus(id, qq.status.CANCELED);\n },\n\n _onComplete: function(id, name, result, xhr) {\n if (!result.success) {\n this._netUploadedOrQueued--;\n this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED);\n\n if (result[this._options.retry.preventRetryResponseProperty] === true) {\n this._preventRetries[id] = true;\n }\n }\n else {\n if (result.thumbnailUrl) {\n this._thumbnailUrls[id] = result.thumbnailUrl;\n }\n\n this._netUploaded++;\n this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL);\n }\n\n this._maybeParseAndSendUploadError(id, name, result, xhr);\n\n return result.success ? true : false;\n },\n\n _onDelete: function(id) {\n this._uploadData.setStatus(id, qq.status.DELETING);\n },\n\n _onDeleteComplete: function(id, xhrOrXdr, isError) {\n var name = this.getName(id);\n\n if (isError) {\n this._uploadData.setStatus(id, qq.status.DELETE_FAILED);\n this.log(\"Delete request for '\" + name + \"' has failed.\", \"error\");\n\n // For error reporting, we only have access to the response status if this is not\n // an `XDomainRequest`.\n if (xhrOrXdr.withCredentials === undefined) {\n this._options.callbacks.onError(id, name, \"Delete request failed\", xhrOrXdr);\n }\n else {\n this._options.callbacks.onError(id, name, \"Delete request failed with response code \" + xhrOrXdr.status, xhrOrXdr);\n }\n }\n else {\n this._netUploadedOrQueued--;\n this._netUploaded--;\n this._handler.expunge(id);\n this._uploadData.setStatus(id, qq.status.DELETED);\n this.log(\"Delete request for '\" + name + \"' has succeeded.\");\n }\n },\n\n _onInputChange: function(input) {\n var fileIndex;\n\n if (qq.supportedFeatures.ajaxUploading) {\n for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) {\n this._annotateWithButtonId(input.files[fileIndex], input);\n }\n\n this.addFiles(input.files);\n }\n // Android 2.3.x will fire `onchange` even if no file has been selected\n else if (input.value.length > 0) {\n this.addFiles(input);\n }\n\n qq.each(this._buttons, function(idx, button) {\n button.reset();\n });\n },\n\n _onProgress: function(id, name, loaded, total) {\n this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total);\n },\n\n _onSubmit: function(id, name) {\n //nothing to do yet in core uploader\n },\n\n _onSubmitCallbackSuccess: function(id, name) {\n this._onSubmit.apply(this, arguments);\n this._uploadData.setStatus(id, qq.status.SUBMITTED);\n this._onSubmitted.apply(this, arguments);\n\n if (this._options.autoUpload) {\n this._options.callbacks.onSubmitted.apply(this, arguments);\n this._uploadFile(id);\n }\n else {\n this._storeForLater(id);\n this._options.callbacks.onSubmitted.apply(this, arguments);\n }\n },\n\n _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) {\n var uuid = this.getUuid(id),\n adjustedOnSuccessCallback;\n\n if (onSuccessCallback) {\n adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams);\n }\n\n if (this._isDeletePossible()) {\n this._handleCheckedCallback({\n name: \"onSubmitDelete\",\n callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id),\n onSuccess: adjustedOnSuccessCallback ||\n qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams),\n identifier: id\n });\n return true;\n }\n else {\n this.log(\"Delete request ignored for ID \" + id + \", delete feature is disabled or request not possible \" +\n \"due to CORS on a user agent that does not support pre-flighting.\", \"warn\");\n return false;\n }\n },\n\n _onSubmitted: function(id) {\n //nothing to do in the base uploader\n },\n\n _onTotalProgress: function(loaded, total) {\n this._options.callbacks.onTotalProgress(loaded, total);\n },\n\n _onUploadPrep: function(id) {\n // nothing to do in the core uploader for now\n },\n\n _onUpload: function(id, name) {\n this._uploadData.setStatus(id, qq.status.UPLOADING);\n },\n\n _onUploadChunk: function(id, chunkData) {\n //nothing to do in the base uploader\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n // Make sure a \"queued\" retry attempt is canceled if the upload has been paused\n if (newStatus === qq.status.PAUSED) {\n clearTimeout(this._retryTimeouts[id]);\n }\n },\n\n _onValidateBatchCallbackFailure: function(fileWrappers) {\n var self = this;\n\n qq.each(fileWrappers, function(idx, fileWrapper) {\n self._fileOrBlobRejected(fileWrapper.id);\n });\n },\n\n _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) {\n var errorMessage,\n itemLimit = this._currentItemLimit,\n proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued;\n\n if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) {\n if (items.length > 0) {\n this._handleCheckedCallback({\n name: \"onValidate\",\n callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button),\n onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint),\n onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint),\n identifier: \"Item '\" + items[0].file.name + \"', size: \" + items[0].file.size\n });\n }\n else {\n this._itemError(\"noFilesError\");\n }\n }\n else {\n this._onValidateBatchCallbackFailure(items);\n errorMessage = this._options.messages.tooManyItemsError\n .replace(/\\{netItems\\}/g, proposedNetFilesUploadedOrQueued)\n .replace(/\\{itemLimit\\}/g, itemLimit);\n this._batchError(errorMessage);\n }\n },\n\n _onValidateCallbackFailure: function(items, index, params, endpoint) {\n var nextIndex = index + 1;\n\n this._fileOrBlobRejected(items[index].id, items[index].file.name);\n\n this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n },\n\n _onValidateCallbackSuccess: function(items, index, params, endpoint) {\n var self = this,\n nextIndex = index + 1,\n validationDescriptor = this._getValidationDescriptor(items[index]);\n\n this._validateFileOrBlobData(items[index], validationDescriptor)\n .then(\n function() {\n self._upload(items[index].id, params, endpoint);\n self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint);\n },\n function() {\n self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint);\n }\n );\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n if (items.length === 0) {\n this._itemError(\"noFilesError\");\n return;\n }\n\n var validationDescriptors = this._getValidationDescriptors(items),\n buttonId = this._getButtonId(items[0].file),\n button = this._getButton(buttonId);\n\n this._handleCheckedCallback({\n name: \"onValidateBatch\",\n callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button),\n onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button),\n onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items),\n identifier: \"batch validation\"\n });\n },\n\n _preventLeaveInProgress: function() {\n var self = this;\n\n this._disposeSupport.attach(window, \"beforeunload\", function(e) {\n if (self.getInProgress()) {\n e = e || window.event;\n // for ie, ff\n e.returnValue = self._options.messages.onLeave;\n // for webkit\n return self._options.messages.onLeave;\n }\n });\n },\n\n // Attempts to refresh session data only if the `qq.Session` module exists\n // and a session endpoint has been specified. The `onSessionRequestComplete`\n // callback will be invoked once the refresh is complete.\n _refreshSessionData: function() {\n var self = this,\n options = this._options.session;\n\n /* jshint eqnull:true */\n if (qq.Session && this._options.session.endpoint != null) {\n if (!this._session) {\n qq.extend(options, {cors: this._options.cors});\n\n options.log = qq.bind(this.log, this);\n options.addFileRecord = qq.bind(this._addCannedFile, this);\n\n this._session = new qq.Session(options);\n }\n\n setTimeout(function() {\n self._session.refresh().then(function(response, xhrOrXdr) {\n self._sessionRequestComplete();\n self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr);\n\n }, function(response, xhrOrXdr) {\n\n self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr);\n });\n }, 0);\n }\n },\n\n _sessionRequestComplete: function() {},\n\n _setSize: function(id, newSize) {\n this._uploadData.updateSize(id, newSize);\n this._totalProgress && this._totalProgress.onNewSize(id);\n },\n\n _shouldAutoRetry: function(id, name, responseJSON) {\n var uploadData = this._uploadData.retrieve({id: id});\n\n /*jshint laxbreak: true */\n if (!this._preventRetries[id]\n && this._options.retry.enableAuto\n && uploadData.status !== qq.status.PAUSED) {\n\n if (this._autoRetries[id] === undefined) {\n this._autoRetries[id] = 0;\n }\n\n if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) {\n this._autoRetries[id] += 1;\n return true;\n }\n }\n\n return false;\n },\n\n _storeForLater: function(id) {\n this._storedIds.push(id);\n },\n\n // Maps a file with the button that was used to select it.\n _trackButton: function(id) {\n var buttonId;\n\n if (qq.supportedFeatures.ajaxUploading) {\n buttonId = this._handler.getFile(id).qqButtonId;\n }\n else {\n buttonId = this._getButtonId(this._handler.getInput(id));\n }\n\n if (buttonId) {\n this._buttonIdsForFileIds[id] = buttonId;\n }\n },\n\n _updateFormSupportAndParams: function(formElementOrId) {\n this._options.form.element = formElementOrId;\n\n this._formSupport = qq.FormSupport && new qq.FormSupport(\n this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)\n );\n\n if (this._formSupport && this._formSupport.attachedToForm) {\n this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);\n\n this._options.autoUpload = this._formSupport.newAutoUpload;\n if (this._formSupport.newEndpoint) {\n this.setEndpoint(this._formSupport.newEndpoint);\n }\n }\n },\n\n _upload: function(id, params, endpoint) {\n var name = this.getName(id);\n\n if (params) {\n this.setParams(params, id);\n }\n\n if (endpoint) {\n this.setEndpoint(endpoint, id);\n }\n\n this._handleCheckedCallback({\n name: \"onSubmit\",\n callback: qq.bind(this._options.callbacks.onSubmit, this, id, name),\n onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name),\n onFailure: qq.bind(this._fileOrBlobRejected, this, id, name),\n identifier: id\n });\n },\n\n _uploadFile: function(id) {\n if (!this._handler.upload(id)) {\n this._uploadData.setStatus(id, qq.status.QUEUED);\n }\n },\n\n _uploadStoredFiles: function() {\n var idToUpload, stillSubmitting,\n self = this;\n\n while (this._storedIds.length) {\n idToUpload = this._storedIds.shift();\n this._uploadFile(idToUpload);\n }\n\n // If we are still waiting for some files to clear validation, attempt to upload these again in a bit\n stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;\n if (stillSubmitting) {\n qq.log(\"Still waiting for \" + stillSubmitting + \" files to clear submit queue. Will re-parse stored IDs array shortly.\");\n setTimeout(function() {\n self._uploadStoredFiles();\n }, 1000);\n }\n },\n\n /**\n * Performs some internal validation checks on an item, defined in the `validation` option.\n *\n * @param fileWrapper Wrapper containing a `file` along with an `id`\n * @param validationDescriptor Normalized information about the item (`size`, `name`).\n * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file\n * @private\n */\n _validateFileOrBlobData: function(fileWrapper, validationDescriptor) {\n var self = this,\n file = (function() {\n if (fileWrapper.file instanceof qq.BlobProxy) {\n return fileWrapper.file.referenceBlob;\n }\n return fileWrapper.file;\n }()),\n name = validationDescriptor.name,\n size = validationDescriptor.size,\n buttonId = this._getButtonId(fileWrapper.file),\n validationBase = this._getValidationBase(buttonId),\n validityChecker = new qq.Promise();\n\n validityChecker.then(\n function() {},\n function() {\n self._fileOrBlobRejected(fileWrapper.id, name);\n });\n\n if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) {\n this._itemError(\"typeError\", name, file);\n return validityChecker.failure();\n }\n\n if (!this._options.validation.allowEmpty && size === 0) {\n this._itemError(\"emptyError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) {\n this._itemError(\"sizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (size > 0 && size < validationBase.minSizeLimit) {\n this._itemError(\"minSizeError\", name, file);\n return validityChecker.failure();\n }\n\n if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) {\n new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(\n validityChecker.success,\n function(errorCode) {\n self._itemError(errorCode + \"ImageError\", name, file);\n validityChecker.failure();\n }\n );\n }\n else {\n validityChecker.success();\n }\n\n return validityChecker;\n },\n\n _wrapCallbacks: function() {\n var self, safeCallback, prop;\n\n self = this;\n\n safeCallback = function(name, callback, args) {\n var errorMsg;\n\n try {\n return callback.apply(self, args);\n }\n catch (exception) {\n errorMsg = exception.message || exception.toString();\n self.log(\"Caught exception in '\" + name + \"' callback - \" + errorMsg, \"error\");\n }\n };\n\n /* jshint forin: false, loopfunc: true */\n for (prop in this._options.callbacks) {\n (function() {\n var callbackName, callbackFunc;\n callbackName = prop;\n callbackFunc = self._options.callbacks[callbackName];\n self._options.callbacks[callbackName] = function() {\n return safeCallback(callbackName, callbackFunc, arguments);\n };\n }());\n }\n }\n };\n}());\n","/*globals qq*/\n(function() {\n \"use strict\";\n\n qq.FineUploaderBasic = function(o) {\n var self = this;\n\n // These options define FineUploaderBasic mode.\n this._options = {\n debug: false,\n button: null,\n multiple: true,\n maxConnections: 3,\n disableCancelForFormUploads: false,\n autoUpload: true,\n\n request: {\n customHeaders: {},\n endpoint: \"/server/upload\",\n filenameParam: \"qqfilename\",\n forceMultipart: true,\n inputName: \"qqfile\",\n method: \"POST\",\n params: {},\n paramsInBody: true,\n totalFileSizeName: \"qqtotalfilesize\",\n uuidName: \"qquuid\"\n },\n\n validation: {\n allowedExtensions: [],\n sizeLimit: 0,\n minSizeLimit: 0,\n itemLimit: 0,\n stopOnFirstInvalidFile: true,\n acceptFiles: null,\n image: {\n maxHeight: 0,\n maxWidth: 0,\n minHeight: 0,\n minWidth: 0\n },\n allowEmpty: false\n },\n\n callbacks: {\n onSubmit: function(id, name) {},\n onSubmitted: function(id, name) {},\n onComplete: function(id, name, responseJSON, maybeXhr) {},\n onAllComplete: function(successful, failed) {},\n onCancel: function(id, name) {},\n onUpload: function(id, name) {},\n onUploadChunk: function(id, name, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onProgress: function(id, name, loaded, total) {},\n onTotalProgress: function(loaded, total) {},\n onError: function(id, name, reason, maybeXhrOrXdr) {},\n onAutoRetry: function(id, name, attemptNumber) {},\n onManualRetry: function(id, name) {},\n onValidateBatch: function(fileOrBlobData) {},\n onValidate: function(fileOrBlobData) {},\n onSubmitDelete: function(id) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {},\n onPasteReceived: function(blob) {},\n onStatusChange: function(id, oldStatus, newStatus) {},\n onSessionRequestComplete: function(response, success, xhrOrXdr) {}\n },\n\n messages: {\n typeError: \"{file} has an invalid extension. Valid extension(s): {extensions}.\",\n sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n emptyError: \"{file} is empty, please select files again without it.\",\n noFilesError: \"No files to upload.\",\n tooManyItemsError: \"Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.\",\n maxHeightImageError: \"Image is too tall.\",\n maxWidthImageError: \"Image is too wide.\",\n minHeightImageError: \"Image is not tall enough.\",\n minWidthImageError: \"Image is not wide enough.\",\n retryFailTooManyItems: \"Retry failed - you have reached your file limit.\",\n onLeave: \"The files are being uploaded, if you leave now the upload will be canceled.\",\n unsupportedBrowserIos8Safari: \"Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues.\"\n },\n\n retry: {\n enableAuto: false,\n maxAutoAttempts: 3,\n autoAttemptDelay: 5,\n preventRetryResponseProperty: \"preventRetry\"\n },\n\n classes: {\n buttonHover: \"qq-upload-button-hover\",\n buttonFocus: \"qq-upload-button-focus\"\n },\n\n chunking: {\n enabled: false,\n concurrent: {\n enabled: false\n },\n mandatory: false,\n paramNames: {\n partIndex: \"qqpartindex\",\n partByteOffset: \"qqpartbyteoffset\",\n chunkSize: \"qqchunksize\",\n totalFileSize: \"qqtotalfilesize\",\n totalParts: \"qqtotalparts\"\n },\n partSize: 2000000,\n // only relevant for traditional endpoints, only required when concurrent.enabled === true\n success: {\n endpoint: null\n }\n },\n\n resume: {\n enabled: false,\n recordsExpireIn: 7, //days\n paramNames: {\n resuming: \"qqresume\"\n }\n },\n\n formatFileName: function(fileOrBlobName) {\n return fileOrBlobName;\n },\n\n text: {\n defaultResponseError: \"Upload failure reason unknown\",\n fileInputTitle: \"file input\",\n sizeSymbols: [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\"]\n },\n\n deleteFile: {\n enabled: false,\n method: \"DELETE\",\n endpoint: \"/server/upload\",\n customHeaders: {},\n params: {}\n },\n\n cors: {\n expected: false,\n sendCredentials: false,\n allowXdr: false\n },\n\n blobs: {\n defaultName: \"misc_data\"\n },\n\n paste: {\n targetElement: null,\n defaultName: \"pasted_image\"\n },\n\n camera: {\n ios: false,\n\n // if ios is true: button is null means target the default button, otherwise target the button specified\n button: null\n },\n\n // This refers to additional upload buttons to be handled by Fine Uploader.\n // Each element is an object, containing `element` as the only required\n // property. The `element` must be a container that will ultimately\n // contain an invisible ` ` created by Fine Uploader.\n // Optional properties of each object include `multiple`, `validation`,\n // and `folders`.\n extraButtons: [],\n\n // Depends on the session module. Used to query the server for an initial file list\n // during initialization and optionally after a `reset`.\n session: {\n endpoint: null,\n params: {},\n customHeaders: {},\n refreshOnReset: true\n },\n\n // Send parameters associated with an existing form along with the files\n form: {\n // Element ID, HTMLElement, or null\n element: \"qq-form\",\n\n // Overrides the base `autoUpload`, unless `element` is null.\n autoUpload: false,\n\n // true = upload files on form submission (and squelch submit event)\n interceptSubmit: true\n },\n\n // scale images client side, upload a new file for each scaled version\n scaling: {\n customResizer: null,\n\n // send the original file as well\n sendOriginal: true,\n\n // fox orientation for scaled images\n orient: true,\n\n // If null, scaled image type will match reference image type. This value will be referred to\n // for any size record that does not specific a type.\n defaultType: null,\n\n defaultQuality: 80,\n\n failureText: \"Failed to scale\",\n\n includeExif: false,\n\n // metadata about each requested scaled version\n sizes: []\n },\n\n workarounds: {\n iosEmptyVideos: true,\n ios8SafariUploads: true,\n ios8BrowserCrash: false\n }\n };\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._buttons = [];\n this._extraButtonSpecs = {};\n this._buttonIdsForFileIds = [];\n\n this._wrapCallbacks();\n this._disposeSupport = new qq.DisposeSupport();\n\n this._storedIds = [];\n this._autoRetries = [];\n this._retryTimeouts = [];\n this._preventRetries = [];\n this._thumbnailUrls = [];\n\n this._netUploadedOrQueued = 0;\n this._netUploaded = 0;\n this._uploadData = this._createUploadDataTracker();\n\n this._initFormSupportAndParams();\n\n this._customHeadersStore = this._createStore(this._options.request.customHeaders);\n this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders);\n\n this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params);\n\n this._endpointStore = this._createStore(this._options.request.endpoint);\n this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint);\n\n this._handler = this._createUploadHandler();\n\n this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler();\n\n if (this._options.button) {\n this._defaultButtonId = this._createUploadButton({\n element: this._options.button,\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._generateExtraButtonSpecs();\n\n this._handleCameraAccess();\n\n if (this._options.paste.targetElement) {\n if (qq.PasteSupport) {\n this._pasteHandler = this._createPasteHandler();\n }\n else {\n this.log(\"Paste support module not found\", \"error\");\n }\n }\n\n this._preventLeaveInProgress();\n\n this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this));\n this._refreshSessionData();\n\n this._succeededSinceLastAllComplete = [];\n this._failedSinceLastAllComplete = [];\n\n this._scaler = (qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this))) || {};\n if (this._scaler.enabled) {\n this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler);\n }\n\n if (qq.TotalProgress && qq.supportedFeatures.progressBar) {\n this._totalProgress = new qq.TotalProgress(\n qq.bind(this._onTotalProgress, this),\n\n function(id) {\n var entry = self._uploadData.retrieve({id: id});\n return (entry && entry.size) || 0;\n }\n );\n }\n\n this._currentItemLimit = this._options.validation.itemLimit;\n };\n\n // Define the private & public API methods.\n qq.FineUploaderBasic.prototype = qq.basePublicApi;\n qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi);\n}());\n","/*globals qq, XDomainRequest*/\n/** Generic class for sending non-upload ajax requests and handling the associated responses **/\nqq.AjaxRequester = function(o) {\n \"use strict\";\n\n var log, shouldParamsBeInQueryString,\n queue = [],\n requestData = {},\n options = {\n acceptHeader: null,\n validMethods: [\"PATCH\", \"POST\", \"PUT\"],\n method: \"POST\",\n contentType: \"application/x-www-form-urlencoded\",\n maxConnections: 3,\n customHeaders: {},\n endpointStore: {},\n paramsStore: {},\n mandatedParams: {},\n allowXRequestedWithAndCacheControl: true,\n successfulResponseCodes: {\n DELETE: [200, 202, 204],\n PATCH: [200, 201, 202, 203, 204],\n POST: [200, 201, 202, 203, 204],\n PUT: [200, 201, 202, 203, 204],\n GET: [200]\n },\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onSend: function(id) {},\n onComplete: function(id, xhrOrXdr, isError) {},\n onProgress: null\n };\n\n qq.extend(options, o);\n log = options.log;\n\n if (qq.indexOf(options.validMethods, options.method) < 0) {\n throw new Error(\"'\" + options.method + \"' is not a supported method for this type of request!\");\n }\n\n // [Simple methods](http://www.w3.org/TR/cors/#simple-method)\n // are defined by the W3C in the CORS spec as a list of methods that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function isSimpleMethod() {\n return qq.indexOf([\"GET\", \"POST\", \"HEAD\"], options.method) >= 0;\n }\n\n // [Simple headers](http://www.w3.org/TR/cors/#simple-header)\n // are defined by the W3C in the CORS spec as a list of headers that, in part,\n // make a CORS request eligible to be exempt from preflighting.\n function containsNonSimpleHeaders(headers) {\n var containsNonSimple = false;\n\n qq.each(containsNonSimple, function(idx, header) {\n if (qq.indexOf([\"Accept\", \"Accept-Language\", \"Content-Language\", \"Content-Type\"], header) < 0) {\n containsNonSimple = true;\n return false;\n }\n });\n\n return containsNonSimple;\n }\n\n function isXdr(xhr) {\n //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.\n return options.cors.expected && xhr.withCredentials === undefined;\n }\n\n // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.\n function getCorsAjaxTransport() {\n var xhrOrXdr;\n\n if (window.XMLHttpRequest || window.ActiveXObject) {\n xhrOrXdr = qq.createXhrInstance();\n\n if (xhrOrXdr.withCredentials === undefined) {\n xhrOrXdr = new XDomainRequest();\n // Workaround for XDR bug in IE9 - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment\n xhrOrXdr.onload = function() {};\n xhrOrXdr.onerror = function() {};\n xhrOrXdr.ontimeout = function() {};\n xhrOrXdr.onprogress = function() {};\n }\n }\n\n return xhrOrXdr;\n }\n\n // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.\n function getXhrOrXdr(id, suppliedXhr) {\n var xhrOrXdr = requestData[id].xhr;\n\n if (!xhrOrXdr) {\n if (suppliedXhr) {\n xhrOrXdr = suppliedXhr;\n }\n else {\n if (options.cors.expected) {\n xhrOrXdr = getCorsAjaxTransport();\n }\n else {\n xhrOrXdr = qq.createXhrInstance();\n }\n }\n\n requestData[id].xhr = xhrOrXdr;\n }\n\n return xhrOrXdr;\n }\n\n // Removes element from queue, sends next request\n function dequeue(id) {\n var i = qq.indexOf(queue, id),\n max = options.maxConnections,\n nextId;\n\n delete requestData[id];\n queue.splice(i, 1);\n\n if (queue.length >= max && i < max) {\n nextId = queue[max - 1];\n sendRequest(nextId);\n }\n }\n\n function onComplete(id, xdrError) {\n var xhr = getXhrOrXdr(id),\n method = options.method,\n isError = xdrError === true;\n\n dequeue(id);\n\n if (isError) {\n log(method + \" request for \" + id + \" has failed\", \"error\");\n }\n else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {\n isError = true;\n log(method + \" request for \" + id + \" has failed - response code \" + xhr.status, \"error\");\n }\n\n options.onComplete(id, xhr, isError);\n }\n\n function getParams(id) {\n var onDemandParams = requestData[id].additionalParams,\n mandatedParams = options.mandatedParams,\n params;\n\n if (options.paramsStore.get) {\n params = options.paramsStore.get(id);\n }\n\n if (onDemandParams) {\n qq.each(onDemandParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n if (mandatedParams) {\n qq.each(mandatedParams, function(name, val) {\n params = params || {};\n params[name] = val;\n });\n }\n\n return params;\n }\n\n function sendRequest(id, optXhr) {\n var xhr = getXhrOrXdr(id, optXhr),\n method = options.method,\n params = getParams(id),\n payload = requestData[id].payload,\n url;\n\n options.onSend(id);\n\n url = createUrl(id, params, requestData[id].additionalQueryParams);\n\n // XDR and XHR status detection APIs differ a bit.\n if (isXdr(xhr)) {\n xhr.onload = getXdrLoadHandler(id);\n xhr.onerror = getXdrErrorHandler(id);\n }\n else {\n xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);\n }\n\n registerForUploadProgress(id);\n\n // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.\n xhr.open(method, url, true);\n\n // Instruct the transport to send cookies along with the CORS request,\n // unless we are using `XDomainRequest`, which is not capable of this.\n if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {\n xhr.withCredentials = true;\n }\n\n setHeaders(id);\n\n log(\"Sending \" + method + \" request for \" + id);\n\n if (payload) {\n xhr.send(payload);\n }\n else if (shouldParamsBeInQueryString || !params) {\n xhr.send();\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/x-www-form-urlencoded\") >= 0) {\n xhr.send(qq.obj2url(params, \"\"));\n }\n else if (params && options.contentType && options.contentType.toLowerCase().indexOf(\"application/json\") >= 0) {\n xhr.send(JSON.stringify(params));\n }\n else {\n xhr.send(params);\n }\n\n return xhr;\n }\n\n function createUrl(id, params, additionalQueryParams) {\n var endpoint = options.endpointStore.get(id),\n addToPath = requestData[id].addToPath;\n\n /*jshint -W116,-W041 */\n if (addToPath != undefined) {\n endpoint += \"/\" + addToPath;\n }\n\n if (shouldParamsBeInQueryString && params) {\n endpoint = qq.obj2url(params, endpoint);\n }\n\n if (additionalQueryParams) {\n endpoint = qq.obj2url(additionalQueryParams, endpoint);\n }\n\n return endpoint;\n }\n\n // Invoked by the UA to indicate a number of possible states that describe\n // a live `XMLHttpRequest` transport.\n function getXhrReadyStateChangeHandler(id) {\n return function() {\n if (getXhrOrXdr(id).readyState === 4) {\n onComplete(id);\n }\n };\n }\n\n function registerForUploadProgress(id) {\n var onProgress = options.onProgress;\n\n if (onProgress) {\n getXhrOrXdr(id).upload.onprogress = function(e) {\n if (e.lengthComputable) {\n onProgress(id, e.loaded, e.total);\n }\n };\n }\n }\n\n // This will be called by IE to indicate **success** for an associated\n // `XDomainRequest` transported request.\n function getXdrLoadHandler(id) {\n return function() {\n onComplete(id);\n };\n }\n\n // This will be called by IE to indicate **failure** for an associated\n // `XDomainRequest` transported request.\n function getXdrErrorHandler(id) {\n return function() {\n onComplete(id, true);\n };\n }\n\n function setHeaders(id) {\n var xhr = getXhrOrXdr(id),\n customHeaders = options.customHeaders,\n onDemandHeaders = requestData[id].additionalHeaders || {},\n method = options.method,\n allHeaders = {};\n\n // If XDomainRequest is being used, we can't set headers, so just ignore this block.\n if (!isXdr(xhr)) {\n options.acceptHeader && xhr.setRequestHeader(\"Accept\", options.acceptHeader);\n\n // Only attempt to add X-Requested-With & Cache-Control if permitted\n if (options.allowXRequestedWithAndCacheControl) {\n // Do not add X-Requested-With & Cache-Control if this is a cross-origin request\n // OR the cross-origin request contains a non-simple method or header.\n // This is done to ensure a preflight is not triggered exclusively based on the\n // addition of these 2 non-simple headers.\n if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {\n xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\n }\n }\n\n if (options.contentType && (method === \"POST\" || method === \"PUT\")) {\n xhr.setRequestHeader(\"Content-Type\", options.contentType);\n }\n\n qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders);\n qq.extend(allHeaders, onDemandHeaders);\n\n qq.each(allHeaders, function(name, val) {\n xhr.setRequestHeader(name, val);\n });\n }\n }\n\n function isResponseSuccessful(responseCode) {\n return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;\n }\n\n function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) {\n requestData[id] = {\n addToPath: addToPath,\n additionalParams: additionalParams,\n additionalQueryParams: additionalQueryParams,\n additionalHeaders: additionalHeaders,\n payload: payload\n };\n\n var len = queue.push(id);\n\n // if too many active connections, wait...\n if (len <= options.maxConnections) {\n return sendRequest(id, optXhr);\n }\n }\n\n shouldParamsBeInQueryString = options.method === \"GET\" || options.method === \"DELETE\";\n\n qq.extend(this, {\n // Start the process of sending the request. The ID refers to the file associated with the request.\n initTransport: function(id) {\n var path, params, headers, payload, cacheBuster, additionalQueryParams;\n\n return {\n // Optionally specify the end of the endpoint path for the request.\n withPath: function(appendToPath) {\n path = appendToPath;\n return this;\n },\n\n // Optionally specify additional parameters to send along with the request.\n // These will be added to the query string for GET/DELETE requests or the payload\n // for POST/PUT requests. The Content-Type of the request will be used to determine\n // how these parameters should be formatted as well.\n withParams: function(additionalParams) {\n params = additionalParams;\n return this;\n },\n\n withQueryParams: function(_additionalQueryParams_) {\n additionalQueryParams = _additionalQueryParams_;\n return this;\n },\n\n // Optionally specify additional headers to send along with the request.\n withHeaders: function(additionalHeaders) {\n headers = additionalHeaders;\n return this;\n },\n\n // Optionally specify a payload/body for the request.\n withPayload: function(thePayload) {\n payload = thePayload;\n return this;\n },\n\n // Appends a cache buster (timestamp) to the request URL as a query parameter (only if GET or DELETE)\n withCacheBuster: function() {\n cacheBuster = true;\n return this;\n },\n\n // Send the constructed request.\n send: function(optXhr) {\n if (cacheBuster && qq.indexOf([\"GET\", \"DELETE\"], options.method) >= 0) {\n params.qqtimestamp = new Date().getTime();\n }\n\n return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload);\n }\n };\n },\n\n canceled: function(id) {\n dequeue(id);\n }\n });\n};\n","/* globals qq */\n/**\n * Common upload handler functions.\n *\n * @constructor\n */\nqq.UploadHandler = function(spec) {\n \"use strict\";\n\n var proxy = spec.proxy,\n fileState = {},\n onCancel = proxy.onCancel,\n getName = proxy.getName;\n\n qq.extend(this, {\n add: function(id, fileItem) {\n fileState[id] = fileItem;\n fileState[id].temp = {};\n },\n\n cancel: function(id) {\n var self = this,\n cancelFinalizationEffort = new qq.Promise(),\n onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort);\n\n onCancelRetVal.then(function() {\n if (self.isValid(id)) {\n fileState[id].canceled = true;\n self.expunge(id);\n }\n cancelFinalizationEffort.success();\n });\n },\n\n expunge: function(id) {\n delete fileState[id];\n },\n\n getThirdPartyFileId: function(id) {\n return fileState[id].key;\n },\n\n isValid: function(id) {\n return fileState[id] !== undefined;\n },\n\n reset: function() {\n fileState = {};\n },\n\n _getFileState: function(id) {\n return fileState[id];\n },\n\n _setThirdPartyFileId: function(id, thirdPartyFileId) {\n fileState[id].key = thirdPartyFileId;\n },\n\n _wasCanceled: function(id) {\n return !!fileState[id].canceled;\n }\n });\n};\n","/*globals qq*/\n/**\n * Base upload handler module. Controls more specific handlers.\n *\n * @param o Options. Passed along to the specific handler submodule as well.\n * @param namespace [optional] Namespace for the specific handler.\n */\nqq.UploadHandlerController = function(o, namespace) {\n \"use strict\";\n\n var controller = this,\n chunkingPossible = false,\n concurrentChunkingPossible = false,\n chunking, preventRetryResponse, log, handler,\n\n options = {\n paramsStore: {},\n maxConnections: 3, // maximum number of concurrent uploads\n chunking: {\n enabled: false,\n multiple: {\n enabled: false\n }\n },\n log: function(str, level) {},\n onProgress: function(id, fileName, loaded, total) {},\n onComplete: function(id, fileName, response, xhr) {},\n onCancel: function(id, fileName) {},\n onUploadPrep: function(id) {}, // Called if non-trivial operations will be performed before onUpload\n onUpload: function(id, fileName) {},\n onUploadChunk: function(id, fileName, chunkData) {},\n onUploadChunkSuccess: function(id, chunkData, response, xhr) {},\n onAutoRetry: function(id, fileName, response, xhr) {},\n onResume: function(id, fileName, chunkData) {},\n onUuidChanged: function(id, newUuid) {},\n getName: function(id) {},\n setSize: function(id, newSize) {},\n isQueued: function(id) {},\n getIdsInProxyGroup: function(id) {},\n getIdsInBatch: function(id) {}\n },\n\n chunked = {\n // Called when each chunk has uploaded successfully\n done: function(id, chunkIdx, response, xhr) {\n var chunkData = handler._getChunkData(id, chunkIdx);\n\n handler._getFileState(id).attemptingResume = false;\n\n delete handler._getFileState(id).temp.chunkProgress[chunkIdx];\n handler._getFileState(id).loaded += chunkData.size;\n\n options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr);\n },\n\n // Called when all chunks have been successfully uploaded and we want to ask the handler to perform any\n // logic associated with closing out the file, such as combining the chunks.\n finalize: function(id) {\n var size = options.getSize(id),\n name = options.getName(id);\n\n log(\"All chunks have been uploaded for \" + id + \" - finalizing....\");\n handler.finalizeChunks(id).then(\n function(response, xhr) {\n log(\"Finalize successful for \" + id);\n\n var normaizedResponse = upload.normalizeResponse(response, true);\n\n options.onProgress(id, name, size, size);\n handler._maybeDeletePersistedChunkData(id);\n upload.cleanup(id, normaizedResponse, xhr);\n },\n function(response, xhr) {\n var normaizedResponse = upload.normalizeResponse(response, false);\n\n log(\"Problem finalizing chunks for file ID \" + id + \" - \" + normaizedResponse.error, \"error\");\n\n if (normaizedResponse.reset) {\n chunked.reset(id);\n }\n\n if (!options.onAutoRetry(id, name, normaizedResponse, xhr)) {\n upload.cleanup(id, normaizedResponse, xhr);\n }\n }\n );\n },\n\n handleFailure: function(chunkIdx, id, response, xhr) {\n var name = options.getName(id);\n\n log(\"Chunked upload request failed for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var responseToReport = upload.normalizeResponse(response, false),\n inProgressIdx;\n\n if (responseToReport.reset) {\n chunked.reset(id);\n }\n else {\n inProgressIdx = qq.indexOf(handler._getFileState(id).chunking.inProgress, chunkIdx);\n if (inProgressIdx >= 0) {\n handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1);\n handler._getFileState(id).chunking.remaining.unshift(chunkIdx);\n }\n }\n\n // We may have aborted all other in-progress chunks for this file due to a failure.\n // If so, ignore the failures associated with those aborts.\n if (!handler._getFileState(id).temp.ignoreFailure) {\n // If this chunk has failed, we want to ignore all other failures of currently in-progress\n // chunks since they will be explicitly aborted\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = true;\n\n log(qq.format(\"Going to attempt to abort these chunks: {}. These are currently in-progress: {}.\", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress)));\n qq.each(handler._getXhrs(id), function(ckid, ckXhr) {\n log(qq.format(\"Attempting to abort file {}.{}. XHR readyState {}. \", id, ckid, ckXhr.readyState));\n ckXhr.abort();\n // Flag the transport, in case we are waiting for some other async operation\n // to complete before attempting to upload the chunk\n ckXhr._cancelled = true;\n });\n\n // We must indicate that all aborted chunks are no longer in progress\n handler.moveInProgressToRemaining(id);\n\n // Free up any connections used by these chunks, but don't allow any\n // other files to take up the connections (until we have exhausted all auto-retries)\n connectionManager.free(id, true);\n }\n\n if (!options.onAutoRetry(id, name, responseToReport, xhr)) {\n // If one chunk fails, abort all of the others to avoid odd race conditions that occur\n // if a chunk succeeds immediately after one fails before we have determined if the upload\n // is a failure or not.\n upload.cleanup(id, responseToReport, xhr);\n }\n }\n },\n\n hasMoreParts: function(id) {\n return !!handler._getFileState(id).chunking.remaining.length;\n },\n\n nextPart: function(id) {\n var nextIdx = handler._getFileState(id).chunking.remaining.shift();\n\n if (nextIdx >= handler._getTotalChunks(id)) {\n nextIdx = null;\n }\n\n return nextIdx;\n },\n\n reset: function(id) {\n log(\"Server or callback has ordered chunking effort to be restarted on next attempt for item ID \" + id, \"error\");\n\n handler._maybeDeletePersistedChunkData(id);\n handler.reevaluateChunking(id);\n handler._getFileState(id).loaded = 0;\n },\n\n sendNext: function(id) {\n var size = options.getSize(id),\n name = options.getName(id),\n chunkIdx = chunked.nextPart(id),\n chunkData = handler._getChunkData(id, chunkIdx),\n resuming = handler._getFileState(id).attemptingResume,\n inProgressChunks = handler._getFileState(id).chunking.inProgress || [];\n\n if (handler._getFileState(id).loaded == null) {\n handler._getFileState(id).loaded = 0;\n }\n\n // Don't follow-through with the resume attempt if the integrator returns false from onResume\n if (resuming && options.onResume(id, name, chunkData) === false) {\n chunked.reset(id);\n chunkIdx = chunked.nextPart(id);\n chunkData = handler._getChunkData(id, chunkIdx);\n resuming = false;\n }\n\n // If all chunks have already uploaded successfully, we must be re-attempting the finalize step.\n if (chunkIdx == null && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n\n // Send the next chunk\n else {\n log(qq.format(\"Sending chunked upload request for item {}.{}, bytes {}-{} of {}.\", id, chunkIdx, chunkData.start + 1, chunkData.end, size));\n options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData));\n inProgressChunks.push(chunkIdx);\n handler._getFileState(id).chunking.inProgress = inProgressChunks;\n\n if (concurrentChunkingPossible) {\n connectionManager.open(id, chunkIdx);\n }\n\n if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) {\n chunked.sendNext(id);\n }\n\n if (chunkData.blob.size === 0) {\n log(qq.format(\"Chunk {} for file {} will not be uploaded, zero sized chunk.\", chunkIdx, id), \"error\");\n chunked.handleFailure(chunkIdx, id, \"File is no longer available\", null);\n }\n else {\n handler.uploadChunk(id, chunkIdx, resuming).then(\n // upload chunk success\n function success(response, xhr) {\n log(\"Chunked upload request succeeded for \" + id + \", chunk \" + chunkIdx);\n\n handler.clearCachedChunk(id, chunkIdx);\n\n var inProgressChunks = handler._getFileState(id).chunking.inProgress || [],\n responseToReport = upload.normalizeResponse(response, true),\n inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx);\n\n log(qq.format(\"Chunk {} for file {} uploaded successfully.\", chunkIdx, id));\n\n chunked.done(id, chunkIdx, responseToReport, xhr);\n\n if (inProgressChunkIdx >= 0) {\n inProgressChunks.splice(inProgressChunkIdx, 1);\n }\n\n handler._maybePersistChunkedState(id);\n\n if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) {\n chunked.finalize(id);\n }\n else if (chunked.hasMoreParts(id)) {\n chunked.sendNext(id);\n }\n else {\n log(qq.format(\"File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}\", id, JSON.stringify(inProgressChunks)));\n }\n },\n\n // upload chunk failure\n function failure(response, xhr) {\n chunked.handleFailure(chunkIdx, id, response, xhr);\n }\n )\n .done(function() {\n handler.clearXhr(id, chunkIdx);\n });\n }\n }\n }\n },\n\n connectionManager = {\n _open: [],\n _openChunks: {},\n _waiting: [],\n\n available: function() {\n var max = options.maxConnections,\n openChunkEntriesCount = 0,\n openChunksCount = 0;\n\n qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) {\n openChunkEntriesCount++;\n openChunksCount += openChunkIndexes.length;\n });\n\n return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount);\n },\n\n /**\n * Removes element from queue, starts upload of next\n */\n free: function(id, dontAllowNext) {\n var allowNext = !dontAllowNext,\n waitingIndex = qq.indexOf(connectionManager._waiting, id),\n connectionsIndex = qq.indexOf(connectionManager._open, id),\n nextId;\n\n delete connectionManager._openChunks[id];\n\n if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) {\n log(\"Generated blob upload has ended for \" + id + \", disposing generated blob.\");\n delete handler._getFileState(id).file;\n }\n\n // If this file was not consuming a connection, it was just waiting, so remove it from the waiting array\n if (waitingIndex >= 0) {\n connectionManager._waiting.splice(waitingIndex, 1);\n }\n // If this file was consuming a connection, allow the next file to be uploaded\n else if (allowNext && connectionsIndex >= 0) {\n connectionManager._open.splice(connectionsIndex, 1);\n\n nextId = connectionManager._waiting.shift();\n if (nextId >= 0) {\n connectionManager._open.push(nextId);\n upload.start(nextId);\n }\n }\n },\n\n getWaitingOrConnected: function() {\n var waitingOrConnected = [];\n\n // Chunked files may have multiple connections open per chunk (if concurrent chunking is enabled)\n // We need to grab the file ID of any file that has at least one chunk consuming a connection.\n qq.each(connectionManager._openChunks, function(fileId, chunks) {\n if (chunks && chunks.length) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // For non-chunked files, only one connection will be consumed per file.\n // This is where we aggregate those file IDs.\n qq.each(connectionManager._open, function(idx, fileId) {\n if (!connectionManager._openChunks[fileId]) {\n waitingOrConnected.push(parseInt(fileId));\n }\n });\n\n // There may be files waiting for a connection.\n waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting);\n\n return waitingOrConnected;\n },\n\n isUsingConnection: function(id) {\n return qq.indexOf(connectionManager._open, id) >= 0;\n },\n\n open: function(id, chunkIdx) {\n if (chunkIdx == null) {\n connectionManager._waiting.push(id);\n }\n\n if (connectionManager.available()) {\n if (chunkIdx == null) {\n connectionManager._waiting.pop();\n connectionManager._open.push(id);\n }\n else {\n (function() {\n var openChunksEntry = connectionManager._openChunks[id] || [];\n openChunksEntry.push(chunkIdx);\n connectionManager._openChunks[id] = openChunksEntry;\n }());\n }\n\n return true;\n }\n\n return false;\n },\n\n reset: function() {\n connectionManager._waiting = [];\n connectionManager._open = [];\n }\n },\n\n simple = {\n send: function(id, name) {\n handler._getFileState(id).loaded = 0;\n\n log(\"Sending simple upload request for \" + id);\n handler.uploadFile(id).then(\n function(response, optXhr) {\n log(\"Simple upload request succeeded for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, true),\n size = options.getSize(id);\n\n options.onProgress(id, name, size, size);\n upload.maybeNewUuid(id, responseToReport);\n upload.cleanup(id, responseToReport, optXhr);\n },\n\n function(response, optXhr) {\n log(\"Simple upload request failed for \" + id);\n\n var responseToReport = upload.normalizeResponse(response, false);\n\n if (!options.onAutoRetry(id, name, responseToReport, optXhr)) {\n upload.cleanup(id, responseToReport, optXhr);\n }\n }\n );\n }\n },\n\n upload = {\n cancel: function(id) {\n log(\"Cancelling \" + id);\n options.paramsStore.remove(id);\n connectionManager.free(id);\n },\n\n cleanup: function(id, response, optXhr) {\n var name = options.getName(id);\n\n options.onComplete(id, name, response, optXhr);\n\n if (handler._getFileState(id)) {\n handler._clearXhrs && handler._clearXhrs(id);\n }\n\n connectionManager.free(id);\n },\n\n // Returns a qq.BlobProxy, or an actual File/Blob if no proxy is involved, or undefined\n // if none of these are available for the ID\n getProxyOrBlob: function(id) {\n return (handler.getProxy && handler.getProxy(id)) ||\n (handler.getFile && handler.getFile(id));\n },\n\n initHandler: function() {\n var handlerType = namespace ? qq[namespace] : qq.traditional,\n handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? \"Xhr\" : \"Form\";\n\n handler = new handlerType[handlerModuleSubtype + \"UploadHandler\"](\n options,\n {\n getDataByUuid: options.getDataByUuid,\n getName: options.getName,\n getSize: options.getSize,\n getUuid: options.getUuid,\n log: log,\n onCancel: options.onCancel,\n onProgress: options.onProgress,\n onUuidChanged: options.onUuidChanged\n }\n );\n\n if (handler._removeExpiredChunkingRecords) {\n handler._removeExpiredChunkingRecords();\n }\n },\n\n isDeferredEligibleForUpload: function(id) {\n return options.isQueued(id);\n },\n\n // For Blobs that are part of a group of generated images, along with a reference image,\n // this will ensure the blobs in the group are uploaded in the order they were triggered,\n // even if some async processing must be completed on one or more Blobs first.\n maybeDefer: function(id, blob) {\n // If we don't have a file/blob yet & no file/blob exists for this item, request it,\n // and then submit the upload to the specific handler once the blob is available.\n // ASSUMPTION: This condition will only ever be true if XHR uploading is supported.\n if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) {\n\n // Blob creation may take some time, so the caller may want to update the\n // UI to indicate that an operation is in progress, even before the actual\n // upload begins and an onUpload callback is invoked.\n options.onUploadPrep(id);\n\n log(\"Attempting to generate a blob on-demand for \" + id);\n blob.create().then(function(generatedBlob) {\n log(\"Generated an on-demand blob for \" + id);\n\n // Update record associated with this file by providing the generated Blob\n handler.updateBlob(id, generatedBlob);\n\n // Propagate the size for this generated Blob\n options.setSize(id, generatedBlob.size);\n\n // Order handler to recalculate chunking possibility, if applicable\n handler.reevaluateChunking(id);\n\n upload.maybeSendDeferredFiles(id);\n },\n\n // Blob could not be generated. Fail the upload & attempt to prevent retries. Also bubble error message.\n function(errorMessage) {\n var errorResponse = {};\n\n if (errorMessage) {\n errorResponse.error = errorMessage;\n }\n\n log(qq.format(\"Failed to generate blob for ID {}. Error message: {}.\", id, errorMessage), \"error\");\n\n options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null);\n upload.maybeSendDeferredFiles(id);\n connectionManager.free(id);\n });\n }\n else {\n return upload.maybeSendDeferredFiles(id);\n }\n\n return false;\n },\n\n // Upload any grouped blobs, in the proper order, that are ready to be uploaded\n maybeSendDeferredFiles: function(id) {\n var idsInGroup = options.getIdsInProxyGroup(id),\n uploadedThisId = false;\n\n if (idsInGroup && idsInGroup.length) {\n log(\"Maybe ready to upload proxy group file \" + id);\n\n qq.each(idsInGroup, function(idx, idInGroup) {\n if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) {\n uploadedThisId = idInGroup === id;\n upload.now(idInGroup);\n }\n else if (upload.isDeferredEligibleForUpload(idInGroup)) {\n return false;\n }\n });\n }\n else {\n uploadedThisId = true;\n upload.now(id);\n }\n\n return uploadedThisId;\n },\n\n maybeNewUuid: function(id, response) {\n if (response.newUuid !== undefined) {\n options.onUuidChanged(id, response.newUuid);\n }\n },\n\n // The response coming from handler implementations may be in various formats.\n // Instead of hoping a promise nested 5 levels deep will always return an object\n // as its first param, let's just normalize the response here.\n normalizeResponse: function(originalResponse, successful) {\n var response = originalResponse;\n\n // The passed \"response\" param may not be a response at all.\n // It could be a string, detailing the error, for example.\n if (!qq.isObject(originalResponse)) {\n response = {};\n\n if (qq.isString(originalResponse) && !successful) {\n response.error = originalResponse;\n }\n }\n\n response.success = successful;\n\n return response;\n },\n\n now: function(id) {\n var name = options.getName(id);\n\n if (!controller.isValid(id)) {\n throw new qq.Error(id + \" is not a valid file ID to upload!\");\n }\n\n options.onUpload(id, name);\n\n if (chunkingPossible && handler._shouldChunkThisFile(id)) {\n chunked.sendNext(id);\n }\n else {\n simple.send(id, name);\n }\n },\n\n start: function(id) {\n var blobToUpload = upload.getProxyOrBlob(id);\n\n if (blobToUpload) {\n return upload.maybeDefer(id, blobToUpload);\n }\n else {\n upload.now(id);\n return true;\n }\n }\n };\n\n qq.extend(this, {\n /**\n * Adds file or file input to the queue\n **/\n add: function(id, file) {\n handler.add.apply(this, arguments);\n },\n\n /**\n * Sends the file identified by id\n */\n upload: function(id) {\n if (connectionManager.open(id)) {\n return upload.start(id);\n }\n return false;\n },\n\n retry: function(id) {\n // On retry, if concurrent chunking has been enabled, we may have aborted all other in-progress chunks\n // for a file when encountering a failed chunk upload. We then signaled the controller to ignore\n // all failures associated with these aborts. We are now retrying, so we don't want to ignore\n // any more failures at this point.\n if (concurrentChunkingPossible) {\n handler._getFileState(id).temp.ignoreFailure = false;\n }\n\n // If we are attempting to retry a file that is already consuming a connection, this is likely an auto-retry.\n // Just go ahead and ask the handler to upload again.\n if (connectionManager.isUsingConnection(id)) {\n return upload.start(id);\n }\n\n // If we are attempting to retry a file that is not currently consuming a connection,\n // this is likely a manual retry attempt. We will need to ensure a connection is available\n // before the retry commences.\n else {\n return controller.upload(id);\n }\n },\n\n /**\n * Cancels file upload by id\n */\n cancel: function(id) {\n var cancelRetVal = handler.cancel(id);\n\n if (qq.isGenericPromise(cancelRetVal)) {\n cancelRetVal.then(function() {\n upload.cancel(id);\n });\n }\n else if (cancelRetVal !== false) {\n upload.cancel(id);\n }\n },\n\n /**\n * Cancels all queued or in-progress uploads\n */\n cancelAll: function() {\n var waitingOrConnected = connectionManager.getWaitingOrConnected(),\n i;\n\n // ensure files are cancelled in reverse order which they were added\n // to avoid a flash of time where a queued file begins to upload before it is canceled\n if (waitingOrConnected.length) {\n for (i = waitingOrConnected.length - 1; i >= 0; i--) {\n controller.cancel(waitingOrConnected[i]);\n }\n }\n\n connectionManager.reset();\n },\n\n // Returns a File, Blob, or the Blob/File for the reference/parent file if the targeted blob is a proxy.\n // Undefined if no file record is available.\n getFile: function(id) {\n if (handler.getProxy && handler.getProxy(id)) {\n return handler.getProxy(id).referenceBlob;\n }\n\n return handler.getFile && handler.getFile(id);\n },\n\n // Returns true if the Blob associated with the ID is related to a proxy s\n isProxied: function(id) {\n return !!(handler.getProxy && handler.getProxy(id));\n },\n\n getInput: function(id) {\n if (handler.getInput) {\n return handler.getInput(id);\n }\n },\n\n reset: function() {\n log(\"Resetting upload handler\");\n controller.cancelAll();\n connectionManager.reset();\n handler.reset();\n },\n\n expunge: function(id) {\n if (controller.isValid(id)) {\n return handler.expunge(id);\n }\n },\n\n /**\n * Determine if the file exists.\n */\n isValid: function(id) {\n return handler.isValid(id);\n },\n\n getResumableFilesData: function() {\n if (handler.getResumableFilesData) {\n return handler.getResumableFilesData();\n }\n return [];\n },\n\n /**\n * This may or may not be implemented, depending on the handler. For handlers where a third-party ID is\n * available (such as the \"key\" for Amazon S3), this will return that value. Otherwise, the return value\n * will be undefined.\n *\n * @param id Internal file ID\n * @returns {*} Some identifier used by a 3rd-party service involved in the upload process\n */\n getThirdPartyFileId: function(id) {\n if (controller.isValid(id)) {\n return handler.getThirdPartyFileId(id);\n }\n },\n\n /**\n * Attempts to pause the associated upload if the specific handler supports this and the file is \"valid\".\n * @param id ID of the upload/file to pause\n * @returns {boolean} true if the upload was paused\n */\n pause: function(id) {\n if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) {\n connectionManager.free(id);\n handler.moveInProgressToRemaining(id);\n return true;\n }\n return false;\n },\n\n // True if the file is eligible for pause/resume.\n isResumable: function(id) {\n return !!handler.isResumable && handler.isResumable(id);\n }\n });\n\n qq.extend(options, o);\n log = options.log;\n chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking;\n concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled;\n\n preventRetryResponse = (function() {\n var response = {};\n\n response[options.preventRetryParam] = true;\n\n return response;\n }());\n\n upload.initHandler();\n};\n","/*globals qq */\n/*jshint -W117 */\nqq.WindowReceiveMessage = function(o) {\n \"use strict\";\n\n var options = {\n log: function(message, level) {}\n },\n callbackWrapperDetachers = {};\n\n qq.extend(options, o);\n\n qq.extend(this, {\n receiveMessage: function(id, callback) {\n var onMessageCallbackWrapper = function(event) {\n callback(event.data);\n };\n\n if (window.postMessage) {\n callbackWrapperDetachers[id] = qq(window).attach(\"message\", onMessageCallbackWrapper);\n }\n else {\n log(\"iframe message passing not supported in this browser!\", \"error\");\n }\n },\n\n stopReceivingMessages: function(id) {\n if (window.postMessage) {\n var detacher = callbackWrapperDetachers[id];\n if (detacher) {\n detacher();\n }\n }\n }\n });\n};\n","/* globals qq */\n/**\n * Common APIs exposed to creators of upload via form/iframe handlers. This is reused and possibly overridden\n * in some cases by specific form upload handlers.\n *\n * @constructor\n */\nqq.FormUploadHandler = function(spec) {\n \"use strict\";\n\n var options = spec.options,\n handler = this,\n proxy = spec.proxy,\n formHandlerInstanceId = qq.getUniqueId(),\n onloadCallbacks = {},\n detachLoadEvents = {},\n postMessageCallbackTimers = {},\n isCors = options.isCors,\n inputName = options.inputName,\n getUuid = proxy.getUuid,\n log = proxy.log,\n corsMessageReceiver = new qq.WindowReceiveMessage({log: log});\n\n /**\n * Remove any trace of the file from the handler.\n *\n * @param id ID of the associated file\n */\n function expungeFile(id) {\n delete detachLoadEvents[id];\n\n // If we are dealing with CORS, we might still be waiting for a response from a loaded iframe.\n // In that case, terminate the timer waiting for a message from the loaded iframe\n // and stop listening for any more messages coming from this iframe.\n if (isCors) {\n clearTimeout(postMessageCallbackTimers[id]);\n delete postMessageCallbackTimers[id];\n corsMessageReceiver.stopReceivingMessages(id);\n }\n\n var iframe = document.getElementById(handler._getIframeName(id));\n if (iframe) {\n // To cancel request set src to something else. We use src=\"javascript:false;\"\n // because it doesn't trigger ie6 prompt on https\n /* jshint scripturl:true */\n iframe.setAttribute(\"src\", \"javascript:false;\");\n\n qq(iframe).remove();\n }\n }\n\n /**\n * @param iframeName `document`-unique Name of the associated iframe\n * @returns {*} ID of the associated file\n */\n function getFileIdForIframeName(iframeName) {\n return iframeName.split(\"_\")[0];\n }\n\n /**\n * Generates an iframe to be used as a target for upload-related form submits. This also adds the iframe\n * to the current `document`. Note that the iframe is hidden from view.\n *\n * @param name Name of the iframe.\n * @returns {HTMLIFrameElement} The created iframe\n */\n function initIframeForUpload(name) {\n var iframe = qq.toElement(\"\");\n\n iframe.setAttribute(\"id\", name);\n\n iframe.style.display = \"none\";\n document.body.appendChild(iframe);\n\n return iframe;\n }\n\n /**\n * If we are in CORS mode, we must listen for messages (containing the server response) from the associated\n * iframe, since we cannot directly parse the content of the iframe due to cross-origin restrictions.\n *\n * @param iframe Listen for messages on this iframe.\n * @param callback Invoke this callback with the message from the iframe.\n */\n function registerPostMessageCallback(iframe, callback) {\n var iframeName = iframe.id,\n fileId = getFileIdForIframeName(iframeName),\n uuid = getUuid(fileId);\n\n onloadCallbacks[uuid] = callback;\n\n // When the iframe has loaded (after the server responds to an upload request)\n // declare the attempt a failure if we don't receive a valid message shortly after the response comes in.\n detachLoadEvents[fileId] = qq(iframe).attach(\"load\", function() {\n if (handler.getInput(fileId)) {\n log(\"Received iframe load event for CORS upload request (iframe name \" + iframeName + \")\");\n\n postMessageCallbackTimers[iframeName] = setTimeout(function() {\n var errorMessage = \"No valid message received from loaded iframe for iframe name \" + iframeName;\n log(errorMessage, \"error\");\n callback({\n error: errorMessage\n });\n }, 1000);\n }\n });\n\n // Listen for messages coming from this iframe. When a message has been received, cancel the timer\n // that declares the upload a failure if a message is not received within a reasonable amount of time.\n corsMessageReceiver.receiveMessage(iframeName, function(message) {\n log(\"Received the following window message: '\" + message + \"'\");\n var fileId = getFileIdForIframeName(iframeName),\n response = handler._parseJsonResponse(message),\n uuid = response.uuid,\n onloadCallback;\n\n if (uuid && onloadCallbacks[uuid]) {\n log(\"Handling response for iframe name \" + iframeName);\n clearTimeout(postMessageCallbackTimers[iframeName]);\n delete postMessageCallbackTimers[iframeName];\n\n handler._detachLoadEvent(iframeName);\n\n onloadCallback = onloadCallbacks[uuid];\n\n delete onloadCallbacks[uuid];\n corsMessageReceiver.stopReceivingMessages(iframeName);\n onloadCallback(response);\n }\n else if (!uuid) {\n log(\"'\" + message + \"' does not contain a UUID - ignoring.\");\n }\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, fileInput) {\n super_.add(id, {input: fileInput});\n\n fileInput.setAttribute(\"name\", inputName);\n\n // remove file input from DOM\n if (fileInput.parentNode) {\n qq(fileInput).remove();\n }\n },\n\n expunge: function(id) {\n expungeFile(id);\n super_.expunge(id);\n },\n\n isValid: function(id) {\n return super_.isValid(id) &&\n handler._getFileState(id).input !== undefined;\n }\n };\n });\n\n qq.extend(this, {\n getInput: function(id) {\n return handler._getFileState(id).input;\n },\n\n /**\n * This function either delegates to a more specific message handler if CORS is involved,\n * or simply registers a callback when the iframe has been loaded that invokes the passed callback\n * after determining if the content of the iframe is accessible.\n *\n * @param iframe Associated iframe\n * @param callback Callback to invoke after we have determined if the iframe content is accessible.\n */\n _attachLoadEvent: function(iframe, callback) {\n /*jslint eqeq: true*/\n var responseDescriptor;\n\n if (isCors) {\n registerPostMessageCallback(iframe, callback);\n }\n else {\n detachLoadEvents[iframe.id] = qq(iframe).attach(\"load\", function() {\n log(\"Received response for \" + iframe.id);\n\n // when we remove iframe from dom\n // the request stops, but in IE load\n // event fires\n if (!iframe.parentNode) {\n return;\n }\n\n try {\n // fixing Opera 10.53\n if (iframe.contentDocument &&\n iframe.contentDocument.body &&\n iframe.contentDocument.body.innerHTML == \"false\") {\n // In Opera event is fired second time\n // when body.innerHTML changed from false\n // to server response approx. after 1 sec\n // when we upload file with iframe\n return;\n }\n }\n catch (error) {\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n log(\"Error when attempting to access iframe during handling of upload response (\" + error.message + \")\", \"error\");\n responseDescriptor = {success: false};\n }\n\n callback(responseDescriptor);\n });\n }\n },\n\n /**\n * Creates an iframe with a specific document-unique name.\n *\n * @param id ID of the associated file\n * @returns {HTMLIFrameElement}\n */\n _createIframe: function(id) {\n var iframeName = handler._getIframeName(id);\n\n return initIframeForUpload(iframeName);\n },\n\n /**\n * Called when we are no longer interested in being notified when an iframe has loaded.\n *\n * @param id Associated file ID\n */\n _detachLoadEvent: function(id) {\n if (detachLoadEvents[id] !== undefined) {\n detachLoadEvents[id]();\n delete detachLoadEvents[id];\n }\n },\n\n /**\n * @param fileId ID of the associated file\n * @returns {string} The `document`-unique name of the iframe\n */\n _getIframeName: function(fileId) {\n return fileId + \"_\" + formHandlerInstanceId;\n },\n\n /**\n * Generates a form element and appends it to the `document`. When the form is submitted, a specific iframe is targeted.\n * The name of the iframe is passed in as a property of the spec parameter, and must be unique in the `document`. Note\n * that the form is hidden from view.\n *\n * @param spec An object containing various properties to be used when constructing the form. Required properties are\n * currently: `method`, `endpoint`, `params`, `paramsInBody`, and `targetName`.\n * @returns {HTMLFormElement} The created form\n */\n _initFormForUpload: function(spec) {\n var method = spec.method,\n endpoint = spec.endpoint,\n params = spec.params,\n paramsInBody = spec.paramsInBody,\n targetName = spec.targetName,\n form = qq.toElement(\" \"),\n url = endpoint;\n\n if (paramsInBody) {\n qq.obj2Inputs(params, form);\n }\n else {\n url = qq.obj2url(params, endpoint);\n }\n\n form.setAttribute(\"action\", url);\n form.setAttribute(\"target\", targetName);\n form.style.display = \"none\";\n document.body.appendChild(form);\n\n return form;\n },\n\n /**\n * @param innerHtmlOrMessage JSON message\n * @returns {*} The parsed response, or an empty object if the response could not be parsed\n */\n _parseJsonResponse: function(innerHtmlOrMessage) {\n var response = {};\n\n try {\n response = qq.parseJson(innerHtmlOrMessage);\n }\n catch (error) {\n log(\"Error when attempting to parse iframe upload response (\" + error.message + \")\", \"error\");\n }\n\n return response;\n }\n });\n};\n","/* globals qq */\n/**\n * Common API exposed to creators of XHR handlers. This is reused and possibly overriding in some cases by specific\n * XHR upload handlers.\n *\n * @constructor\n */\nqq.XhrUploadHandler = function(spec) {\n \"use strict\";\n\n var handler = this,\n namespace = spec.options.namespace,\n proxy = spec.proxy,\n chunking = spec.options.chunking,\n resume = spec.options.resume,\n chunkFiles = chunking && spec.options.chunking.enabled && qq.supportedFeatures.chunking,\n resumeEnabled = resume && spec.options.resume.enabled && chunkFiles && qq.supportedFeatures.resume,\n getName = proxy.getName,\n getSize = proxy.getSize,\n getUuid = proxy.getUuid,\n getEndpoint = proxy.getEndpoint,\n getDataByUuid = proxy.getDataByUuid,\n onUuidChanged = proxy.onUuidChanged,\n onProgress = proxy.onProgress,\n log = proxy.log;\n\n function abort(id) {\n qq.each(handler._getXhrs(id), function(xhrId, xhr) {\n var ajaxRequester = handler._getAjaxRequester(id, xhrId);\n\n xhr.onreadystatechange = null;\n xhr.upload.onprogress = null;\n xhr.abort();\n ajaxRequester && ajaxRequester.canceled && ajaxRequester.canceled(id);\n });\n }\n\n qq.extend(this, new qq.UploadHandler(spec));\n\n qq.override(this, function(super_) {\n return {\n /**\n * Adds File or Blob to the queue\n **/\n add: function(id, blobOrProxy) {\n if (qq.isFile(blobOrProxy) || qq.isBlob(blobOrProxy)) {\n super_.add(id, {file: blobOrProxy});\n }\n else if (blobOrProxy instanceof qq.BlobProxy) {\n super_.add(id, {proxy: blobOrProxy});\n }\n else {\n throw new Error(\"Passed obj is not a File, Blob, or proxy\");\n }\n\n handler._initTempState(id);\n resumeEnabled && handler._maybePrepareForResume(id);\n },\n\n expunge: function(id) {\n abort(id);\n handler._maybeDeletePersistedChunkData(id);\n handler._clearXhrs(id);\n super_.expunge(id);\n }\n };\n });\n\n qq.extend(this, {\n // Clear the cached chunk `Blob` after we are done with it, just in case the `Blob` bytes are stored in memory.\n clearCachedChunk: function(id, chunkIdx) {\n delete handler._getFileState(id).temp.cachedChunks[chunkIdx];\n },\n\n clearXhr: function(id, chunkIdx) {\n var tempState = handler._getFileState(id).temp;\n\n if (tempState.xhrs) {\n delete tempState.xhrs[chunkIdx];\n }\n if (tempState.ajaxRequesters) {\n delete tempState.ajaxRequesters[chunkIdx];\n }\n },\n\n // Called when all chunks have been successfully uploaded. Expected promissory return type.\n // This defines the default behavior if nothing further is required when all chunks have been uploaded.\n finalizeChunks: function(id, responseParser) {\n var lastChunkIdx = handler._getTotalChunks(id) - 1,\n xhr = handler._getXhr(id, lastChunkIdx);\n\n if (responseParser) {\n return new qq.Promise().success(responseParser(xhr), xhr);\n }\n\n return new qq.Promise().success({}, xhr);\n },\n\n getFile: function(id) {\n return handler.isValid(id) && handler._getFileState(id).file;\n },\n\n getProxy: function(id) {\n return handler.isValid(id) && handler._getFileState(id).proxy;\n },\n\n /**\n * @returns {Array} Array of objects containing properties useful to integrators\n * when it is important to determine which files are potentially resumable.\n */\n getResumableFilesData: function() {\n var resumableFilesData = [];\n\n handler._iterateResumeRecords(function(key, uploadData) {\n handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);\n\n var data = {\n name: uploadData.name,\n remaining: uploadData.chunking.remaining,\n size: uploadData.size,\n uuid: uploadData.uuid\n };\n\n if (uploadData.key) {\n data.key = uploadData.key;\n }\n\n resumableFilesData.push(data);\n });\n\n return resumableFilesData;\n },\n\n isResumable: function(id) {\n return !!chunking && handler.isValid(id) && !handler._getFileState(id).notResumable;\n },\n\n moveInProgressToRemaining: function(id, optInProgress, optRemaining) {\n var inProgress = optInProgress || handler._getFileState(id).chunking.inProgress,\n remaining = optRemaining || handler._getFileState(id).chunking.remaining;\n\n if (inProgress) {\n log(qq.format(\"Moving these chunks from in-progress {}, to remaining.\", JSON.stringify(inProgress)));\n inProgress.reverse();\n qq.each(inProgress, function(idx, chunkIdx) {\n remaining.unshift(chunkIdx);\n });\n inProgress.length = 0;\n }\n },\n\n pause: function(id) {\n if (handler.isValid(id)) {\n log(qq.format(\"Aborting XHR upload for {} '{}' due to pause instruction.\", id, getName(id)));\n handler._getFileState(id).paused = true;\n abort(id);\n return true;\n }\n },\n\n reevaluateChunking: function(id) {\n if (chunking && handler.isValid(id)) {\n var state = handler._getFileState(id),\n totalChunks,\n i;\n\n delete state.chunking;\n\n state.chunking = {};\n totalChunks = handler._getTotalChunks(id);\n if (totalChunks > 1 || chunking.mandatory) {\n state.chunking.enabled = true;\n state.chunking.parts = totalChunks;\n state.chunking.remaining = [];\n\n for (i = 0; i < totalChunks; i++) {\n state.chunking.remaining.push(i);\n }\n\n handler._initTempState(id);\n }\n else {\n state.chunking.enabled = false;\n }\n }\n },\n\n updateBlob: function(id, newBlob) {\n if (handler.isValid(id)) {\n handler._getFileState(id).file = newBlob;\n }\n },\n\n _clearXhrs: function(id) {\n var tempState = handler._getFileState(id).temp;\n\n qq.each(tempState.ajaxRequesters, function(chunkId) {\n delete tempState.ajaxRequesters[chunkId];\n });\n\n qq.each(tempState.xhrs, function(chunkId) {\n delete tempState.xhrs[chunkId];\n });\n },\n\n /**\n * Creates an XHR instance for this file and stores it in the fileState.\n *\n * @param id File ID\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @returns {XMLHttpRequest}\n */\n _createXhr: function(id, optChunkIdx) {\n return handler._registerXhr(id, optChunkIdx, qq.createXhrInstance());\n },\n\n _getAjaxRequester: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.ajaxRequesters[chunkIdx];\n },\n\n _getChunkData: function(id, chunkIndex) {\n var chunkSize = chunking.partSize,\n fileSize = getSize(id),\n fileOrBlob = handler.getFile(id),\n startBytes = chunkSize * chunkIndex,\n endBytes = startBytes + chunkSize >= fileSize ? fileSize : startBytes + chunkSize,\n totalChunks = handler._getTotalChunks(id),\n cachedChunks = this._getFileState(id).temp.cachedChunks,\n\n // To work around a Webkit GC bug, we must keep each chunk `Blob` in scope until we are done with it.\n // See https://github.com/Widen/fine-uploader/issues/937#issuecomment-41418760\n blob = cachedChunks[chunkIndex] || qq.sliceBlob(fileOrBlob, startBytes, endBytes);\n\n cachedChunks[chunkIndex] = blob;\n\n return {\n part: chunkIndex,\n start: startBytes,\n end: endBytes,\n count: totalChunks,\n blob: blob,\n size: endBytes - startBytes\n };\n },\n\n _getChunkDataForCallback: function(chunkData) {\n return {\n partIndex: chunkData.part,\n startByte: chunkData.start + 1,\n endByte: chunkData.end,\n totalParts: chunkData.count\n };\n },\n\n /**\n * @param id File ID\n * @returns {string} Identifier for this item that may appear in the browser's local storage\n */\n _getLocalStorageId: function(id) {\n var formatVersion = \"5.0\",\n name = getName(id),\n size = getSize(id),\n chunkSize = chunking.partSize,\n endpoint = getEndpoint(id);\n\n return qq.format(\"qq{}resume{}-{}-{}-{}-{}\", namespace, formatVersion, name, size, chunkSize, endpoint);\n },\n\n _getMimeType: function(id) {\n return handler.getFile(id).type;\n },\n\n _getPersistableData: function(id) {\n return handler._getFileState(id).chunking;\n },\n\n /**\n * @param id ID of the associated file\n * @returns {number} Number of parts this file can be divided into, or undefined if chunking is not supported in this UA\n */\n _getTotalChunks: function(id) {\n if (chunking) {\n var fileSize = getSize(id),\n chunkSize = chunking.partSize;\n\n return Math.ceil(fileSize / chunkSize);\n }\n },\n\n _getXhr: function(id, optChunkIdx) {\n var chunkIdx = optChunkIdx == null ? -1 : optChunkIdx;\n return handler._getFileState(id).temp.xhrs[chunkIdx];\n },\n\n _getXhrs: function(id) {\n return handler._getFileState(id).temp.xhrs;\n },\n\n // Iterates through all XHR handler-created resume records (in local storage),\n // invoking the passed callback and passing in the key and value of each local storage record.\n _iterateResumeRecords: function(callback) {\n if (resumeEnabled) {\n qq.each(localStorage, function(key, item) {\n if (key.indexOf(qq.format(\"qq{}resume\", namespace)) === 0) {\n var uploadData = JSON.parse(item);\n callback(key, uploadData);\n }\n });\n }\n },\n\n _initTempState: function(id) {\n handler._getFileState(id).temp = {\n ajaxRequesters: {},\n chunkProgress: {},\n xhrs: {},\n cachedChunks: {}\n };\n },\n\n _markNotResumable: function(id) {\n handler._getFileState(id).notResumable = true;\n },\n\n // Removes a chunked upload record from local storage, if possible.\n // Returns true if the item was removed, false otherwise.\n _maybeDeletePersistedChunkData: function(id) {\n var localStorageId;\n\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n if (localStorageId && localStorage.getItem(localStorageId)) {\n localStorage.removeItem(localStorageId);\n return true;\n }\n }\n\n return false;\n },\n\n // If this is a resumable upload, grab the relevant data from storage and items in memory that track this upload\n // so we can pick up from where we left off.\n _maybePrepareForResume: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // Resume is enabled and possible and this is the first time we've tried to upload this file in this session,\n // so prepare for a resume attempt.\n if (resumeEnabled && state.key === undefined) {\n localStorageId = handler._getLocalStorageId(id);\n persistedData = localStorage.getItem(localStorageId);\n\n // If we found this item in local storage, maybe we should resume it.\n if (persistedData) {\n persistedData = JSON.parse(persistedData);\n\n // If we found a resume record but we have already handled this file in this session,\n // don't try to resume it & ensure we don't persist future check data\n if (getDataByUuid(persistedData.uuid)) {\n handler._markNotResumable(id);\n }\n else {\n log(qq.format(\"Identified file with ID {} and name of {} as resumable.\", id, getName(id)));\n\n onUuidChanged(id, persistedData.uuid);\n\n state.key = persistedData.key;\n state.chunking = persistedData.chunking;\n state.loaded = persistedData.loaded;\n state.attemptingResume = true;\n\n handler.moveInProgressToRemaining(id);\n }\n }\n }\n },\n\n // Persist any data needed to resume this upload in a new session.\n _maybePersistChunkedState: function(id) {\n var state = handler._getFileState(id),\n localStorageId, persistedData;\n\n // If local storage isn't supported by the browser, or if resume isn't enabled or possible, give up\n if (resumeEnabled && handler.isResumable(id)) {\n localStorageId = handler._getLocalStorageId(id);\n\n persistedData = {\n name: getName(id),\n size: getSize(id),\n uuid: getUuid(id),\n key: state.key,\n chunking: state.chunking,\n loaded: state.loaded,\n lastUpdated: Date.now()\n };\n\n try {\n localStorage.setItem(localStorageId, JSON.stringify(persistedData));\n }\n catch (error) {\n log(qq.format(\"Unable to save resume data for '{}' due to error: '{}'.\", id, error.toString()), \"warn\");\n }\n }\n },\n\n _registerProgressHandler: function(id, chunkIdx, chunkSize) {\n var xhr = handler._getXhr(id, chunkIdx),\n name = getName(id),\n progressCalculator = {\n simple: function(loaded, total) {\n var fileSize = getSize(id);\n\n if (loaded === total) {\n onProgress(id, name, fileSize, fileSize);\n }\n else {\n onProgress(id, name, (loaded >= fileSize ? fileSize - 1 : loaded), fileSize);\n }\n },\n\n chunked: function(loaded, total) {\n var chunkProgress = handler._getFileState(id).temp.chunkProgress,\n totalSuccessfullyLoadedForFile = handler._getFileState(id).loaded,\n loadedForRequest = loaded,\n totalForRequest = total,\n totalFileSize = getSize(id),\n estActualChunkLoaded = loadedForRequest - (totalForRequest - chunkSize),\n totalLoadedForFile = totalSuccessfullyLoadedForFile;\n\n chunkProgress[chunkIdx] = estActualChunkLoaded;\n\n qq.each(chunkProgress, function(chunkIdx, chunkLoaded) {\n totalLoadedForFile += chunkLoaded;\n });\n\n onProgress(id, name, totalLoadedForFile, totalFileSize);\n }\n };\n\n xhr.upload.onprogress = function(e) {\n if (e.lengthComputable) {\n /* jshint eqnull: true */\n var type = chunkSize == null ? \"simple\" : \"chunked\";\n progressCalculator[type](e.loaded, e.total);\n }\n };\n },\n\n /**\n * Registers an XHR transport instance created elsewhere.\n *\n * @param id ID of the associated file\n * @param optChunkIdx The chunk index associated with this XHR, if applicable\n * @param xhr XMLHttpRequest object instance\n * @param optAjaxRequester `qq.AjaxRequester` associated with this request, if applicable.\n * @returns {XMLHttpRequest}\n */\n _registerXhr: function(id, optChunkIdx, xhr, optAjaxRequester) {\n var xhrsId = optChunkIdx == null ? -1 : optChunkIdx,\n tempState = handler._getFileState(id).temp;\n\n tempState.xhrs = tempState.xhrs || {};\n tempState.ajaxRequesters = tempState.ajaxRequesters || {};\n\n tempState.xhrs[xhrsId] = xhr;\n\n if (optAjaxRequester) {\n tempState.ajaxRequesters[xhrsId] = optAjaxRequester;\n }\n\n return xhr;\n },\n\n // Deletes any local storage records that are \"expired\".\n _removeExpiredChunkingRecords: function() {\n var expirationDays = resume.recordsExpireIn;\n\n handler._iterateResumeRecords(function(key, uploadData) {\n var expirationDate = new Date(uploadData.lastUpdated);\n\n // transform updated date into expiration date\n expirationDate.setDate(expirationDate.getDate() + expirationDays);\n\n if (expirationDate.getTime() <= Date.now()) {\n log(\"Removing expired resume record with key \" + key);\n localStorage.removeItem(key);\n }\n });\n },\n\n /**\n * Determine if the associated file should be chunked.\n *\n * @param id ID of the associated file\n * @returns {*} true if chunking is enabled, possible, and the file can be split into more than 1 part\n */\n _shouldChunkThisFile: function(id) {\n var state = handler._getFileState(id);\n\n if (!state.chunking) {\n handler.reevaluateChunking(id);\n }\n\n return state.chunking.enabled;\n }\n });\n};\n","/*globals qq, XMLHttpRequest*/\nqq.DeleteFileAjaxRequester = function(o) {\n \"use strict\";\n\n var requester,\n options = {\n method: \"DELETE\",\n uuidParamName: \"qquuid\",\n endpointStore: {},\n maxConnections: 3,\n customHeaders: function(id) {return {};},\n paramsStore: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n log: function(str, level) {},\n onDelete: function(id) {},\n onDeleteComplete: function(id, xhrOrXdr, isError) {}\n };\n\n qq.extend(options, o);\n\n function getMandatedParams() {\n if (options.method.toUpperCase() === \"POST\") {\n return {\n _method: \"DELETE\"\n };\n }\n\n return {};\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"POST\", \"DELETE\"],\n method: options.method,\n endpointStore: options.endpointStore,\n paramsStore: options.paramsStore,\n mandatedParams: getMandatedParams(),\n maxConnections: options.maxConnections,\n customHeaders: function(id) {\n return options.customHeaders.get(id);\n },\n log: options.log,\n onSend: options.onDelete,\n onComplete: options.onDeleteComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n sendDelete: function(id, uuid, additionalMandatedParams) {\n var additionalOptions = additionalMandatedParams || {};\n\n options.log(\"Submitting delete file request for \" + id);\n\n if (options.method === \"DELETE\") {\n requester.initTransport(id)\n .withPath(uuid)\n .withParams(additionalOptions)\n .send();\n }\n else {\n additionalOptions[options.uuidParamName] = uuid;\n requester.initTransport(id)\n .withParams(additionalOptions)\n .send();\n }\n }\n });\n};\n","/*global qq, define */\n/*jshint strict:false,bitwise:false,nonew:false,asi:true,-W064,-W116,-W089 */\n/**\n * Mega pixel image rendering library for iOS6+\n *\n * Fixes iOS6+'s image file rendering issue for large size image (over mega-pixel),\n * which causes unexpected subsampling when drawing it in canvas.\n * By using this library, you can safely render the image with proper stretching.\n *\n * Copyright (c) 2012 Shinichi Tomita \n * Released under the MIT license\n *\n * Heavily modified by Widen for Fine Uploader\n */\n(function() {\n\n /**\n * Detect subsampling in loaded image.\n * In iOS, larger images than 2M pixels may be subsampled in rendering.\n */\n function detectSubsampling(img) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n canvas = document.createElement(\"canvas\"),\n ctx;\n\n if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image\n canvas.width = canvas.height = 1;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, -iw + 1, 0);\n // subsampled image becomes half smaller in rendering size.\n // check alpha channel value to confirm image is covering edge pixel or not.\n // if alpha value is 0 image is not covering, hence subsampled.\n return ctx.getImageData(0, 0, 1, 1).data[3] === 0;\n } else {\n return false;\n }\n }\n\n /**\n * Detecting vertical squash in loaded image.\n * Fixes a bug which squash image vertically while drawing into canvas for some images.\n */\n function detectVerticalSquash(img, iw, ih) {\n var canvas = document.createElement(\"canvas\"),\n sy = 0,\n ey = ih,\n py = ih,\n ctx, data, alpha, ratio;\n\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n\n // search image edge pixel position in case it is squashed vertically.\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n\n ratio = (py / ih);\n return (ratio === 0) ? 1 : ratio;\n }\n\n /**\n * Rendering image element (with resizing) and get its data URL\n */\n function renderImageToDataURL(img, blob, options, doSquash) {\n var canvas = document.createElement(\"canvas\"),\n mime = options.mime || \"image/jpeg\",\n promise = new qq.Promise();\n\n renderImageToCanvas(img, blob, canvas, options, doSquash)\n .then(function() {\n promise.success(\n canvas.toDataURL(mime, options.quality || 0.8)\n );\n });\n\n return promise;\n }\n\n function maybeCalculateDownsampledDimensions(spec) {\n var maxPixels = 5241000; //iOS specific value\n\n if (!qq.ios()) {\n throw new qq.Error(\"Downsampled dimensions can only be reliably calculated for iOS!\");\n }\n\n if (spec.origHeight * spec.origWidth > maxPixels) {\n return {\n newHeight: Math.round(Math.sqrt(maxPixels * (spec.origHeight / spec.origWidth))),\n newWidth: Math.round(Math.sqrt(maxPixels * (spec.origWidth / spec.origHeight)))\n };\n }\n }\n\n /**\n * Rendering image element (with resizing) into the canvas element\n */\n function renderImageToCanvas(img, blob, canvas, options, doSquash) {\n var iw = img.naturalWidth,\n ih = img.naturalHeight,\n width = options.width,\n height = options.height,\n ctx = canvas.getContext(\"2d\"),\n promise = new qq.Promise(),\n modifiedDimensions;\n\n ctx.save();\n\n if (options.resize) {\n return renderImageToCanvasWithCustomResizer({\n blob: blob,\n canvas: canvas,\n image: img,\n imageHeight: ih,\n imageWidth: iw,\n orientation: options.orientation,\n resize: options.resize,\n targetHeight: height,\n targetWidth: width\n });\n }\n\n if (!qq.supportedFeatures.unlimitedScaledImageSize) {\n modifiedDimensions = maybeCalculateDownsampledDimensions({\n origWidth: width,\n origHeight: height\n });\n\n if (modifiedDimensions) {\n qq.log(qq.format(\"Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h\",\n width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),\n \"warn\");\n\n width = modifiedDimensions.newWidth;\n height = modifiedDimensions.newHeight;\n }\n }\n\n transformCoordinate(canvas, width, height, options.orientation);\n\n // Fine Uploader specific: Save some CPU cycles if not using iOS\n // Assumption: This logic is only needed to overcome iOS image sampling issues\n if (qq.ios()) {\n (function() {\n if (detectSubsampling(img)) {\n iw /= 2;\n ih /= 2;\n }\n\n var d = 1024, // size of tiling canvas\n tmpCanvas = document.createElement(\"canvas\"),\n vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1,\n dw = Math.ceil(d * width / iw),\n dh = Math.ceil(d * height / ih / vertSquashRatio),\n sy = 0,\n dy = 0,\n tmpCtx, sx, dx;\n\n tmpCanvas.width = tmpCanvas.height = d;\n tmpCtx = tmpCanvas.getContext(\"2d\");\n\n while (sy < ih) {\n sx = 0;\n dx = 0;\n while (sx < iw) {\n tmpCtx.clearRect(0, 0, d, d);\n tmpCtx.drawImage(img, -sx, -sy);\n ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);\n sx += d;\n dx += dw;\n }\n sy += d;\n dy += dh;\n }\n ctx.restore();\n tmpCanvas = tmpCtx = null;\n }());\n }\n else {\n ctx.drawImage(img, 0, 0, width, height);\n }\n\n canvas.qqImageRendered && canvas.qqImageRendered();\n promise.success();\n\n return promise;\n }\n\n function renderImageToCanvasWithCustomResizer(resizeInfo) {\n var blob = resizeInfo.blob,\n image = resizeInfo.image,\n imageHeight = resizeInfo.imageHeight,\n imageWidth = resizeInfo.imageWidth,\n orientation = resizeInfo.orientation,\n promise = new qq.Promise(),\n resize = resizeInfo.resize,\n sourceCanvas = document.createElement(\"canvas\"),\n sourceCanvasContext = sourceCanvas.getContext(\"2d\"),\n targetCanvas = resizeInfo.canvas,\n targetHeight = resizeInfo.targetHeight,\n targetWidth = resizeInfo.targetWidth;\n\n transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);\n\n targetCanvas.height = targetHeight;\n targetCanvas.width = targetWidth;\n\n sourceCanvasContext.drawImage(image, 0, 0);\n\n resize({\n blob: blob,\n height: targetHeight,\n image: image,\n sourceCanvas: sourceCanvas,\n targetCanvas: targetCanvas,\n width: targetWidth\n })\n .then(\n function success() {\n targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();\n promise.success();\n },\n promise.failure\n );\n\n return promise;\n }\n\n /**\n * Transform canvas coordination according to specified frame size and orientation\n * Orientation value is from EXIF tag\n */\n function transformCoordinate(canvas, width, height, orientation) {\n switch (orientation) {\n case 5:\n case 6:\n case 7:\n case 8:\n canvas.width = height;\n canvas.height = width;\n break;\n default:\n canvas.width = width;\n canvas.height = height;\n }\n var ctx = canvas.getContext(\"2d\");\n switch (orientation) {\n case 2:\n // horizontal flip\n ctx.translate(width, 0);\n ctx.scale(-1, 1);\n break;\n case 3:\n // 180 rotate left\n ctx.translate(width, height);\n ctx.rotate(Math.PI);\n break;\n case 4:\n // vertical flip\n ctx.translate(0, height);\n ctx.scale(1, -1);\n break;\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.scale(1, -1);\n break;\n case 6:\n // 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(0, -height);\n break;\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI);\n ctx.translate(width, -height);\n ctx.scale(-1, 1);\n break;\n case 8:\n // 90 rotate left\n ctx.rotate(-0.5 * Math.PI);\n ctx.translate(-width, 0);\n break;\n default:\n break;\n }\n }\n\n /**\n * MegaPixImage class\n */\n function MegaPixImage(srcImage, errorCallback) {\n var self = this;\n\n if (window.Blob && srcImage instanceof Blob) {\n (function() {\n var img = new Image(),\n URL = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;\n if (!URL) { throw Error(\"No createObjectURL function found to create blob url\"); }\n img.src = URL.createObjectURL(srcImage);\n self.blob = srcImage;\n srcImage = img;\n }());\n }\n if (!srcImage.naturalWidth && !srcImage.naturalHeight) {\n srcImage.onload = function() {\n var listeners = self.imageLoadListeners;\n if (listeners) {\n self.imageLoadListeners = null;\n // IE11 doesn't reliably report actual image dimensions immediately after onload for small files,\n // so let's push this to the end of the UI thread queue.\n setTimeout(function() {\n for (var i = 0, len = listeners.length; i < len; i++) {\n listeners[i]();\n }\n }, 0);\n }\n };\n srcImage.onerror = errorCallback;\n this.imageLoadListeners = [];\n }\n this.srcImage = srcImage;\n }\n\n /**\n * Rendering megapix image into specified target element\n */\n MegaPixImage.prototype.render = function(target, options) {\n options = options || {};\n\n var self = this,\n imgWidth = this.srcImage.naturalWidth,\n imgHeight = this.srcImage.naturalHeight,\n width = options.width,\n height = options.height,\n maxWidth = options.maxWidth,\n maxHeight = options.maxHeight,\n doSquash = !this.blob || this.blob.type === \"image/jpeg\",\n tagName = target.tagName.toLowerCase(),\n opt;\n\n if (this.imageLoadListeners) {\n this.imageLoadListeners.push(function() { self.render(target, options); });\n return;\n }\n\n if (width && !height) {\n height = (imgHeight * width / imgWidth) << 0;\n } else if (height && !width) {\n width = (imgWidth * height / imgHeight) << 0;\n } else {\n width = imgWidth;\n height = imgHeight;\n }\n if (maxWidth && width > maxWidth) {\n width = maxWidth;\n height = (imgHeight * width / imgWidth) << 0;\n }\n if (maxHeight && height > maxHeight) {\n height = maxHeight;\n width = (imgWidth * height / imgHeight) << 0;\n }\n\n opt = { width: width, height: height },\n qq.each(options, function(optionsKey, optionsValue) {\n opt[optionsKey] = optionsValue;\n });\n\n if (tagName === \"img\") {\n (function() {\n var oldTargetSrc = target.src;\n renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)\n .then(function(dataUri) {\n target.src = dataUri;\n oldTargetSrc === target.src && target.onload();\n });\n }());\n } else if (tagName === \"canvas\") {\n renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);\n }\n if (typeof this.onrender === \"function\") {\n this.onrender(target);\n }\n };\n\n qq.MegaPixImage = MegaPixImage;\n})();\n","/*globals qq */\n/**\n * Draws a thumbnail of a Blob/File/URL onto an or .\n *\n * @constructor\n */\nqq.ImageGenerator = function(log) {\n \"use strict\";\n\n function isImg(el) {\n return el.tagName.toLowerCase() === \"img\";\n }\n\n function isCanvas(el) {\n return el.tagName.toLowerCase() === \"canvas\";\n }\n\n function isImgCorsSupported() {\n return new Image().crossOrigin !== undefined;\n }\n\n function isCanvasSupported() {\n var canvas = document.createElement(\"canvas\");\n\n return canvas.getContext && canvas.getContext(\"2d\");\n }\n\n // This is only meant to determine the MIME type of a renderable image file.\n // It is used to ensure images drawn from a URL that have transparent backgrounds\n // are rendered correctly, among other things.\n function determineMimeOfFileName(nameWithPath) {\n /*jshint -W015 */\n var pathSegments = nameWithPath.split(\"/\"),\n name = pathSegments[pathSegments.length - 1].split(\"?\")[0],\n extension = qq.getExtension(name);\n\n extension = extension && extension.toLowerCase();\n\n switch (extension) {\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"bmp\":\n return \"image/bmp\";\n case \"gif\":\n return \"image/gif\";\n case \"tiff\":\n case \"tif\":\n return \"image/tiff\";\n }\n }\n\n // This will likely not work correctly in IE8 and older.\n // It's only used as part of a formula to determine\n // if a canvas can be used to scale a server-hosted thumbnail.\n // If canvas isn't supported by the UA (IE8 and older)\n // this method should not even be called.\n function isCrossOrigin(url) {\n var targetAnchor = document.createElement(\"a\"),\n targetProtocol, targetHostname, targetPort;\n\n targetAnchor.href = url;\n\n targetProtocol = targetAnchor.protocol;\n targetPort = targetAnchor.port;\n targetHostname = targetAnchor.hostname;\n\n if (targetProtocol.toLowerCase() !== window.location.protocol.toLowerCase()) {\n return true;\n }\n\n if (targetHostname.toLowerCase() !== window.location.hostname.toLowerCase()) {\n return true;\n }\n\n // IE doesn't take ports into consideration when determining if two endpoints are same origin.\n if (targetPort !== window.location.port && !qq.ie()) {\n return true;\n }\n\n return false;\n }\n\n function registerImgLoadListeners(img, promise) {\n img.onload = function() {\n img.onload = null;\n img.onerror = null;\n promise.success(img);\n };\n\n img.onerror = function() {\n img.onload = null;\n img.onerror = null;\n log(\"Problem drawing thumbnail!\", \"error\");\n promise.failure(img, \"Problem drawing thumbnail!\");\n };\n }\n\n function registerCanvasDrawImageListener(canvas, promise) {\n // The image is drawn on the canvas by a third-party library,\n // and we want to know when this is completed. Since the library\n // may invoke drawImage many times in a loop, we need to be called\n // back when the image is fully rendered. So, we are expecting the\n // code that draws this image to follow a convention that involves a\n // function attached to the canvas instance be invoked when it is done.\n canvas.qqImageRendered = function() {\n promise.success(canvas);\n };\n }\n\n // Fulfills a `qq.Promise` when an image has been drawn onto the target,\n // whether that is a or an . The attempt is considered a\n // failure if the target is not an or a , or if the drawing\n // attempt was not successful.\n function registerThumbnailRenderedListener(imgOrCanvas, promise) {\n var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas);\n\n if (isImg(imgOrCanvas)) {\n registerImgLoadListeners(imgOrCanvas, promise);\n }\n else if (isCanvas(imgOrCanvas)) {\n registerCanvasDrawImageListener(imgOrCanvas, promise);\n }\n else {\n promise.failure(imgOrCanvas);\n log(qq.format(\"Element container of type {} is not supported!\", imgOrCanvas.tagName), \"error\");\n }\n\n return registered;\n }\n\n // Draw a preview iff the current UA can natively display it.\n // Also rotate the image if necessary.\n function draw(fileOrBlob, container, options) {\n var drawPreview = new qq.Promise(),\n identifier = new qq.Identify(fileOrBlob, log),\n maxSize = options.maxSize,\n // jshint eqnull:true\n orient = options.orient == null ? true : options.orient,\n megapixErrorHandler = function() {\n container.onerror = null;\n container.onload = null;\n log(\"Could not render preview, file may be too large!\", \"error\");\n drawPreview.failure(container, \"Browser cannot render image!\");\n };\n\n identifier.isPreviewable().then(\n function(mime) {\n // If options explicitly specify that Orientation is not desired,\n // replace the orient task with a dummy promise that \"succeeds\" immediately.\n var dummyExif = {\n parse: function() {\n return new qq.Promise().success();\n }\n },\n exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif,\n mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler);\n\n if (registerThumbnailRenderedListener(container, drawPreview)) {\n exif.parse().then(\n function(exif) {\n var orientation = exif && exif.Orientation;\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n orientation: orientation,\n mime: mime,\n resize: options.customResizeFunction\n });\n },\n\n function(failureMsg) {\n log(qq.format(\"EXIF data could not be parsed ({}). Assuming orientation = 1.\", failureMsg));\n\n mpImg.render(container, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: mime,\n resize: options.customResizeFunction\n });\n }\n );\n }\n },\n\n function() {\n log(\"Not previewable\");\n drawPreview.failure(container, \"Not previewable\");\n }\n );\n\n return drawPreview;\n }\n\n function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {\n var tempImg = new Image(),\n tempImgRender = new qq.Promise();\n\n registerThumbnailRenderedListener(tempImg, tempImgRender);\n\n if (isCrossOrigin(url)) {\n tempImg.crossOrigin = \"anonymous\";\n }\n\n tempImg.src = url;\n\n tempImgRender.then(\n function rendered() {\n registerThumbnailRenderedListener(canvasOrImg, draw);\n\n var mpImg = new qq.MegaPixImage(tempImg);\n mpImg.render(canvasOrImg, {\n maxWidth: maxSize,\n maxHeight: maxSize,\n mime: determineMimeOfFileName(url),\n resize: customResizeFunction\n });\n },\n\n draw.failure\n );\n }\n\n function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) {\n registerThumbnailRenderedListener(img, draw);\n // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images\n // that must drop back to CSS is known and exploited by the templating module.\n // In this module, we pre-render \"waiting\" thumbs for all files immediately after they\n // are submitted, and we must be sure to pass any style associated with the \"waiting\" preview.\n qq(img).css({\n maxWidth: maxSize + \"px\",\n maxHeight: maxSize + \"px\"\n });\n\n img.src = url;\n }\n\n // Draw a (server-hosted) thumbnail given a URL.\n // This will optionally scale the thumbnail as well.\n // It attempts to use to scale, but will fall back\n // to max-width and max-height style properties if the UA\n // doesn't support canvas or if the images is cross-domain and\n // the UA doesn't support the crossorigin attribute on img tags,\n // which is required to scale a cross-origin image using &\n // then export it back to an .\n function drawFromUrl(url, container, options) {\n var draw = new qq.Promise(),\n scale = options.scale,\n maxSize = scale ? options.maxSize : null;\n\n // container is an img, scaling needed\n if (scale && isImg(container)) {\n // Iff canvas is available in this UA, try to use it for scaling.\n // Otherwise, fall back to CSS scaling\n if (isCanvasSupported()) {\n // Attempt to use for image scaling,\n // but we must fall back to scaling via CSS/styles\n // if this is a cross-origin image and the UA doesn't support CORS.\n if (isCrossOrigin(url) && !isImgCorsSupported()) {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n else {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n }\n else {\n drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize);\n }\n }\n // container is a canvas, scaling optional\n else if (isCanvas(container)) {\n drawOnCanvasOrImgFromUrl(url, container, draw, maxSize);\n }\n // container is an img & no scaling: just set the src attr to the passed url\n else if (registerThumbnailRenderedListener(container, draw)) {\n container.src = url;\n }\n\n return draw;\n }\n\n qq.extend(this, {\n /**\n * Generate a thumbnail. Depending on the arguments, this may either result in\n * a client-side rendering of an image (if a `Blob` is supplied) or a server-generated\n * image that may optionally be scaled client-side using or CSS/styles (as a fallback).\n *\n * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image\n * @param container or to contain the preview\n * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.\n * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed\n */\n generate: function(fileBlobOrUrl, container, options) {\n if (qq.isString(fileBlobOrUrl)) {\n log(\"Attempting to update thumbnail based on server response.\");\n return drawFromUrl(fileBlobOrUrl, container, options || {});\n }\n else {\n log(\"Attempting to draw client-side image preview.\");\n return draw(fileBlobOrUrl, container, options || {});\n }\n }\n });\n\n /**/\n this._testing = {};\n this._testing.isImg = isImg;\n this._testing.isCanvas = isCanvas;\n this._testing.isCrossOrigin = isCrossOrigin;\n this._testing.determineMimeOfFileName = determineMimeOfFileName;\n /* */\n};\n","/*globals qq */\n/**\n * EXIF image data parser. Currently only parses the Orientation tag value,\n * but this may be expanded to other tags in the future.\n *\n * @param fileOrBlob Attempt to parse EXIF data in this `Blob`\n * @constructor\n */\nqq.Exif = function(fileOrBlob, log) {\n \"use strict\";\n\n // Orientation is the only tag parsed here at this time.\n var TAG_IDS = [274],\n TAG_INFO = {\n 274: {\n name: \"Orientation\",\n bytes: 2\n }\n };\n\n // Convert a little endian (hex string) to big endian (decimal).\n function parseLittleEndian(hex) {\n var result = 0,\n pow = 0;\n\n while (hex.length > 0) {\n result += parseInt(hex.substring(0, 2), 16) * Math.pow(2, pow);\n hex = hex.substring(2, hex.length);\n pow += 8;\n }\n\n return result;\n }\n\n // Find the byte offset, of Application Segment 1 (EXIF).\n // External callers need not supply any arguments.\n function seekToApp1(offset, promise) {\n var theOffset = offset,\n thePromise = promise;\n if (theOffset === undefined) {\n theOffset = 2;\n thePromise = new qq.Promise();\n }\n\n qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) {\n var match = /^ffe([0-9])/.exec(hex),\n segmentLength;\n\n if (match) {\n if (match[1] !== \"1\") {\n segmentLength = parseInt(hex.slice(4, 8), 16);\n seekToApp1(theOffset + segmentLength + 2, thePromise);\n }\n else {\n thePromise.success(theOffset);\n }\n }\n else {\n thePromise.failure(\"No EXIF header to be found!\");\n }\n });\n\n return thePromise;\n }\n\n // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only.\n function getApp1Offset() {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) {\n if (hex.indexOf(\"ffd8\") !== 0) {\n promise.failure(\"Not a valid JPEG!\");\n }\n else {\n seekToApp1().then(function(offset) {\n promise.success(offset);\n },\n function(error) {\n promise.failure(error);\n });\n }\n });\n\n return promise;\n }\n\n // Determine the byte ordering of the EXIF header.\n function isLittleEndian(app1Start) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) {\n promise.success(hex === \"4949\");\n });\n\n return promise;\n }\n\n // Determine the number of directory entries in the EXIF header.\n function getDirEntryCount(app1Start, littleEndian) {\n var promise = new qq.Promise();\n\n qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) {\n if (littleEndian) {\n return promise.success(parseLittleEndian(hex));\n }\n else {\n promise.success(parseInt(hex, 16));\n }\n });\n\n return promise;\n }\n\n // Get the IFD portion of the EXIF header as a hex string.\n function getIfd(app1Start, dirEntries) {\n var offset = app1Start + 20,\n bytes = dirEntries * 12;\n\n return qq.readBlobToHex(fileOrBlob, offset, bytes);\n }\n\n // Obtain an array of all directory entries (as hex strings) in the EXIF header.\n function getDirEntries(ifdHex) {\n var entries = [],\n offset = 0;\n\n while (offset + 24 <= ifdHex.length) {\n entries.push(ifdHex.slice(offset, offset + 24));\n offset += 24;\n }\n\n return entries;\n }\n\n // Obtain values for all relevant tags and return them.\n function getTagValues(littleEndian, dirEntries) {\n var TAG_VAL_OFFSET = 16,\n tagsToFind = qq.extend([], TAG_IDS),\n vals = {};\n\n qq.each(dirEntries, function(idx, entry) {\n var idHex = entry.slice(0, 4),\n id = littleEndian ? parseLittleEndian(idHex) : parseInt(idHex, 16),\n tagsToFindIdx = tagsToFind.indexOf(id),\n tagValHex, tagName, tagValLength;\n\n if (tagsToFindIdx >= 0) {\n tagName = TAG_INFO[id].name;\n tagValLength = TAG_INFO[id].bytes;\n tagValHex = entry.slice(TAG_VAL_OFFSET, TAG_VAL_OFFSET + (tagValLength * 2));\n vals[tagName] = littleEndian ? parseLittleEndian(tagValHex) : parseInt(tagValHex, 16);\n\n tagsToFind.splice(tagsToFindIdx, 1);\n }\n\n if (tagsToFind.length === 0) {\n return false;\n }\n });\n\n return vals;\n }\n\n qq.extend(this, {\n /**\n * Attempt to parse the EXIF header for the `Blob` associated with this instance.\n *\n * @returns {qq.Promise} To be fulfilled when the parsing is complete.\n * If successful, the parsed EXIF header as an object will be included.\n */\n parse: function() {\n var parser = new qq.Promise(),\n onParseFailure = function(message) {\n log(qq.format(\"EXIF header parse failed: '{}' \", message));\n parser.failure(message);\n };\n\n getApp1Offset().then(function(app1Offset) {\n log(qq.format(\"Moving forward with EXIF header parsing for '{}'\", fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name));\n\n isLittleEndian(app1Offset).then(function(littleEndian) {\n\n log(qq.format(\"EXIF Byte order is {} endian\", littleEndian ? \"little\" : \"big\"));\n\n getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) {\n\n log(qq.format(\"Found {} APP1 directory entries\", dirEntryCount));\n\n getIfd(app1Offset, dirEntryCount).then(function(ifdHex) {\n var dirEntries = getDirEntries(ifdHex),\n tagValues = getTagValues(littleEndian, dirEntries);\n\n log(\"Successfully parsed some EXIF tags\");\n\n parser.success(tagValues);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n }, onParseFailure);\n\n return parser;\n }\n });\n\n /**/\n this._testing = {};\n this._testing.parseLittleEndian = parseLittleEndian;\n /* */\n};\n","/*globals qq */\nqq.Identify = function(fileOrBlob, log) {\n \"use strict\";\n\n function isIdentifiable(magicBytes, questionableBytes) {\n var identifiable = false,\n magicBytesEntries = [].concat(magicBytes);\n\n qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {\n if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {\n identifiable = true;\n return false;\n }\n });\n\n return identifiable;\n }\n\n qq.extend(this, {\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by reading magic\n * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the\n * file, we will examine the blob's type attribute to save CPU cycles.\n *\n * @returns {qq.Promise} Promise that is fulfilled when identification is complete.\n * If successful, the MIME string is passed to the success handler.\n */\n isPreviewable: function() {\n var self = this,\n identifier = new qq.Promise(),\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n log(qq.format(\"Attempting to determine if {} can be rendered in this browser\", name));\n\n log(\"First pass: check type attribute of blob object.\");\n\n if (this.isPreviewableSync()) {\n log(\"Second pass: check for magic bytes in file header.\");\n\n qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {\n qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {\n if (isIdentifiable(bytes, hex)) {\n // Safari is the only supported browser that can deal with TIFFs natively,\n // so, if this is a TIFF and the UA isn't Safari, declare this file \"non-previewable\".\n if (mime !== \"image/tiff\" || qq.supportedFeatures.tiffPreviews) {\n previewable = true;\n identifier.success(mime);\n }\n\n return false;\n }\n });\n\n log(qq.format(\"'{}' is {} able to be rendered in this browser\", name, previewable ? \"\" : \"NOT\"));\n\n if (!previewable) {\n identifier.failure();\n }\n },\n function() {\n log(\"Error reading file w/ name '\" + name + \"'. Not able to be rendered in this browser.\");\n identifier.failure();\n });\n }\n else {\n identifier.failure();\n }\n\n return identifier;\n },\n\n /**\n * Determines if a Blob can be displayed natively in the current browser. This is done by checking the\n * blob's type attribute. This is a synchronous operation, useful for situations where an asynchronous operation\n * would be challenging to support. Note that the blob's type property is not as accurate as reading the\n * file's magic bytes.\n *\n * @returns {Boolean} true if the blob can be rendered in the current browser\n */\n isPreviewableSync: function() {\n var fileMime = fileOrBlob.type,\n // Assumption: This will only ever be executed in browsers that support `Object.keys`.\n isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0,\n previewable = false,\n name = fileOrBlob.name === undefined ? \"blob\" : fileOrBlob.name;\n\n if (isRecognizedImage) {\n if (fileMime === \"image/tiff\") {\n previewable = qq.supportedFeatures.tiffPreviews;\n }\n else {\n previewable = true;\n }\n }\n\n !previewable && log(name + \" is not previewable in this browser per the blob's type attr\");\n\n return previewable;\n }\n });\n};\n\nqq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {\n \"image/jpeg\": \"ffd8ff\",\n \"image/gif\": \"474946\",\n \"image/png\": \"89504e\",\n \"image/bmp\": \"424d\",\n \"image/tiff\": [\"49492a00\", \"4d4d002a\"]\n};\n","/*globals qq*/\n/**\n * Attempts to validate an image, wherever possible.\n *\n * @param blob File or Blob representing a user-selecting image.\n * @param log Uses this to post log messages to the console.\n * @constructor\n */\nqq.ImageValidation = function(blob, log) {\n \"use strict\";\n\n /**\n * @param limits Object with possible image-related limits to enforce.\n * @returns {boolean} true if at least one of the limits has a non-zero value\n */\n function hasNonZeroLimits(limits) {\n var atLeastOne = false;\n\n qq.each(limits, function(limit, value) {\n if (value > 0) {\n atLeastOne = true;\n return false;\n }\n });\n\n return atLeastOne;\n }\n\n /**\n * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height.\n * Otherwise, `success` is called on the returned promise with an object containing\n * `width` and `height` properties.\n */\n function getWidthHeight() {\n var sizeDetermination = new qq.Promise();\n\n new qq.Identify(blob, log).isPreviewable().then(function() {\n var image = new Image(),\n url = window.URL && window.URL.createObjectURL ? window.URL :\n window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :\n null;\n\n if (url) {\n image.onerror = function() {\n log(\"Cannot determine dimensions for image. May be too large.\", \"error\");\n sizeDetermination.failure();\n };\n\n image.onload = function() {\n sizeDetermination.success({\n width: this.width,\n height: this.height\n });\n };\n\n image.src = url.createObjectURL(blob);\n }\n else {\n log(\"No createObjectURL function available to generate image URL!\", \"error\");\n sizeDetermination.failure();\n }\n }, sizeDetermination.failure);\n\n return sizeDetermination;\n }\n\n /**\n *\n * @param limits Object with possible image-related limits to enforce.\n * @param dimensions Object containing `width` & `height` properties for the image to test.\n * @returns {String || undefined} The name of the failing limit. Undefined if no failing limits.\n */\n function getFailingLimit(limits, dimensions) {\n var failingLimit;\n\n qq.each(limits, function(limitName, limitValue) {\n if (limitValue > 0) {\n var limitMatcher = /(max|min)(Width|Height)/.exec(limitName),\n dimensionPropName = limitMatcher[2].charAt(0).toLowerCase() + limitMatcher[2].slice(1),\n actualValue = dimensions[dimensionPropName];\n\n /*jshint -W015*/\n switch (limitMatcher[1]) {\n case \"min\":\n if (actualValue < limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n case \"max\":\n if (actualValue > limitValue) {\n failingLimit = limitName;\n return false;\n }\n break;\n }\n }\n });\n\n return failingLimit;\n }\n\n /**\n * Validate the associated blob.\n *\n * @param limits\n * @returns {qq.Promise} `success` is called on the promise is the image is valid or\n * if the blob is not an image, or if the image is not verifiable.\n * Otherwise, `failure` with the name of the failing limit.\n */\n this.validate = function(limits) {\n var validationEffort = new qq.Promise();\n\n log(\"Attempting to validate image.\");\n\n if (hasNonZeroLimits(limits)) {\n getWidthHeight().then(function(dimensions) {\n var failingLimit = getFailingLimit(limits, dimensions);\n\n if (failingLimit) {\n validationEffort.failure(failingLimit);\n }\n else {\n validationEffort.success();\n }\n }, validationEffort.success);\n }\n else {\n validationEffort.success();\n }\n\n return validationEffort;\n };\n};\n","/* globals qq */\n/**\n * Module used to control populating the initial list of files.\n *\n * @constructor\n */\nqq.Session = function(spec) {\n \"use strict\";\n\n var options = {\n endpoint: null,\n params: {},\n customHeaders: {},\n cors: {},\n addFileRecord: function(sessionData) {},\n log: function(message, level) {}\n };\n\n qq.extend(options, spec, true);\n\n function isJsonResponseValid(response) {\n if (qq.isArray(response)) {\n return true;\n }\n\n options.log(\"Session response is not an array.\", \"error\");\n }\n\n function handleFileItems(fileItems, success, xhrOrXdr, promise) {\n var someItemsIgnored = false;\n\n success = success && isJsonResponseValid(fileItems);\n\n if (success) {\n qq.each(fileItems, function(idx, fileItem) {\n /* jshint eqnull:true */\n if (fileItem.uuid == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid UUID - ignoring.\", idx), \"error\");\n }\n else if (fileItem.name == null) {\n someItemsIgnored = true;\n options.log(qq.format(\"Session response item {} did not include a valid name - ignoring.\", idx), \"error\");\n }\n else {\n try {\n options.addFileRecord(fileItem);\n return true;\n }\n catch (err) {\n someItemsIgnored = true;\n options.log(err.message, \"error\");\n }\n }\n\n return false;\n });\n }\n\n promise[success && !someItemsIgnored ? \"success\" : \"failure\"](fileItems, xhrOrXdr);\n }\n\n // Initiate a call to the server that will be used to populate the initial file list.\n // Returns a `qq.Promise`.\n this.refresh = function() {\n /*jshint indent:false */\n var refreshEffort = new qq.Promise(),\n refreshCompleteCallback = function(response, success, xhrOrXdr) {\n handleFileItems(response, success, xhrOrXdr, refreshEffort);\n },\n requesterOptions = qq.extend({}, options),\n requester = new qq.SessionAjaxRequester(\n qq.extend(requesterOptions, {onComplete: refreshCompleteCallback})\n );\n\n requester.queryServer();\n\n return refreshEffort;\n };\n};\n","/*globals qq, XMLHttpRequest*/\n/**\n * Thin module used to send GET requests to the server, expecting information about session\n * data used to initialize an uploader instance.\n *\n * @param spec Various options used to influence the associated request.\n * @constructor\n */\nqq.SessionAjaxRequester = function(spec) {\n \"use strict\";\n\n var requester,\n options = {\n endpoint: null,\n customHeaders: {},\n params: {},\n cors: {\n expected: false,\n sendCredentials: false\n },\n onComplete: function(response, success, xhrOrXdr) {},\n log: function(str, level) {}\n };\n\n qq.extend(options, spec);\n\n function onComplete(id, xhrOrXdr, isError) {\n var response = null;\n\n /* jshint eqnull:true */\n if (xhrOrXdr.responseText != null) {\n try {\n response = qq.parseJson(xhrOrXdr.responseText);\n }\n catch (err) {\n options.log(\"Problem parsing session response: \" + err.message, \"error\");\n isError = true;\n }\n }\n\n options.onComplete(response, !isError, xhrOrXdr);\n }\n\n requester = qq.extend(this, new qq.AjaxRequester({\n acceptHeader: \"application/json\",\n validMethods: [\"GET\"],\n method: \"GET\",\n endpointStore: {\n get: function() {\n return options.endpoint;\n }\n },\n customHeaders: options.customHeaders,\n log: options.log,\n onComplete: onComplete,\n cors: options.cors\n }));\n\n qq.extend(this, {\n queryServer: function() {\n var params = qq.extend({}, options.params);\n\n options.log(\"Session query request.\");\n\n requester.initTransport(\"sessionRefresh\")\n .withParams(params)\n .withCacheBuster()\n .send();\n }\n });\n};\n","/* globals qq, ExifRestorer */\n/**\n * Controls generation of scaled images based on a reference image encapsulated in a `File` or `Blob`.\n * Scaled images are generated and converted to blobs on-demand.\n * Multiple scaled images per reference image with varying sizes and other properties are supported.\n *\n * @param spec Information about the scaled images to generate.\n * @param log Logger instance\n * @constructor\n */\nqq.Scaler = function(spec, log) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizer,\n includeOriginal = spec.sendOriginal,\n orient = spec.orient,\n defaultType = spec.defaultType,\n defaultQuality = spec.defaultQuality / 100,\n failedToScaleText = spec.failureText,\n includeExif = spec.includeExif,\n sizes = this._getSortedSizes(spec.sizes);\n\n // Revealed API for instances of this module\n qq.extend(this, {\n // If no targeted sizes have been declared or if this browser doesn't support\n // client-side image preview generation, there is no scaling to do.\n enabled: qq.supportedFeatures.scaling && sizes.length > 0,\n\n getFileRecords: function(originalFileUuid, originalFileName, originalBlobOrBlobData) {\n var self = this,\n records = [],\n originalBlob = originalBlobOrBlobData.blob ? originalBlobOrBlobData.blob : originalBlobOrBlobData,\n identifier = new qq.Identify(originalBlob, log);\n\n // If the reference file cannot be rendered natively, we can't create scaled versions.\n if (identifier.isPreviewableSync()) {\n // Create records for each scaled version & add them to the records array, smallest first.\n qq.each(sizes, function(idx, sizeRecord) {\n var outputType = self._determineOutputType({\n defaultType: defaultType,\n requestedType: sizeRecord.type,\n refType: originalBlob.type\n });\n\n records.push({\n uuid: qq.getUniqueId(),\n name: self._getName(originalFileName, {\n name: sizeRecord.name,\n type: outputType,\n refType: originalBlob.type\n }),\n blob: new qq.BlobProxy(originalBlob,\n qq.bind(self._generateScaledImage, self, {\n customResizeFunction: customResizeFunction,\n maxSize: sizeRecord.maxSize,\n orient: orient,\n type: outputType,\n quality: defaultQuality,\n failedText: failedToScaleText,\n includeExif: includeExif,\n log: log\n }))\n });\n });\n\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: includeOriginal ? originalBlob : null\n });\n }\n else {\n records.push({\n uuid: originalFileUuid,\n name: originalFileName,\n size: originalBlob.size,\n blob: originalBlob\n });\n }\n\n return records;\n },\n\n handleNewFile: function(file, name, uuid, size, fileList, batchId, uuidParamName, api) {\n var self = this,\n buttonId = file.qqButtonId || (file.blob && file.blob.qqButtonId),\n scaledIds = [],\n originalId = null,\n addFileToHandler = api.addFileToHandler,\n uploadData = api.uploadData,\n paramsStore = api.paramsStore,\n proxyGroupId = qq.getUniqueId();\n\n qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {\n var blobSize = record.size,\n id;\n\n if (record.blob instanceof qq.BlobProxy) {\n blobSize = -1;\n }\n\n id = uploadData.addFile({\n uuid: record.uuid,\n name: record.name,\n size: blobSize,\n batchId: batchId,\n proxyGroupId: proxyGroupId\n });\n\n if (record.blob instanceof qq.BlobProxy) {\n scaledIds.push(id);\n }\n else {\n originalId = id;\n }\n\n if (record.blob) {\n addFileToHandler(id, record.blob);\n fileList.push({id: id, file: record.blob});\n }\n else {\n uploadData.setStatus(id, qq.status.REJECTED);\n }\n });\n\n // If we are potentially uploading an original file and some scaled versions,\n // ensure the scaled versions include reference's to the parent's UUID and size\n // in their associated upload requests.\n if (originalId !== null) {\n qq.each(scaledIds, function(idx, scaledId) {\n var params = {\n qqparentuuid: uploadData.retrieve({id: originalId}).uuid,\n qqparentsize: uploadData.retrieve({id: originalId}).size\n };\n\n // Make sure the UUID for each scaled image is sent with the upload request,\n // to be consistent (since we may need to ensure it is sent for the original file as well).\n params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;\n\n uploadData.setParentId(scaledId, originalId);\n paramsStore.addReadOnly(scaledId, params);\n });\n\n // If any scaled images are tied to this parent image, be SURE we send its UUID as an upload request\n // parameter as well.\n if (scaledIds.length) {\n (function() {\n var param = {};\n param[uuidParamName] = uploadData.retrieve({id: originalId}).uuid;\n paramsStore.addReadOnly(originalId, param);\n }());\n }\n }\n }\n });\n};\n\nqq.extend(qq.Scaler.prototype, {\n scaleImage: function(id, specs, api) {\n \"use strict\";\n\n if (!qq.supportedFeatures.scaling) {\n throw new qq.Error(\"Scaling is not supported in this browser!\");\n }\n\n var scalingEffort = new qq.Promise(),\n log = api.log,\n file = api.getFile(id),\n uploadData = api.uploadData.retrieve({id: id}),\n name = uploadData && uploadData.name,\n uuid = uploadData && uploadData.uuid,\n scalingOptions = {\n customResizer: specs.customResizer,\n sendOriginal: false,\n orient: specs.orient,\n defaultType: specs.type || null,\n defaultQuality: specs.quality,\n failedToScaleText: \"Unable to scale\",\n sizes: [{name: \"\", maxSize: specs.maxSize}]\n },\n scaler = new qq.Scaler(scalingOptions, log);\n\n if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) {\n scalingEffort.failure();\n\n log(\"Could not generate requested scaled image for \" + id + \". \" +\n \"Scaling is either not possible in this browser, or the file could not be located.\", \"error\");\n }\n else {\n (qq.bind(function() {\n // Assumption: There will never be more than one record\n var record = scaler.getFileRecords(uuid, name, file)[0];\n\n if (record && record.blob instanceof qq.BlobProxy) {\n record.blob.create().then(scalingEffort.success, scalingEffort.failure);\n }\n else {\n log(id + \" is not a scalable image!\", \"error\");\n scalingEffort.failure();\n }\n }, this)());\n }\n\n return scalingEffort;\n },\n\n // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format.\n // image/jpeg and image/png are the only safe choices at this time.\n _determineOutputType: function(spec) {\n \"use strict\";\n\n var requestedType = spec.requestedType,\n defaultType = spec.defaultType,\n referenceType = spec.refType;\n\n // If a default type and requested type have not been specified, this should be a\n // JPEG if the original type is a JPEG, otherwise, a PNG.\n if (!defaultType && !requestedType) {\n if (referenceType !== \"image/jpeg\") {\n return \"image/png\";\n }\n return referenceType;\n }\n\n // A specified default type is used when a requested type is not specified.\n if (!requestedType) {\n return defaultType;\n }\n\n // If requested type is specified, use it, as long as this recognized type is supported by the current UA\n if (qq.indexOf(Object.keys(qq.Identify.prototype.PREVIEWABLE_MIME_TYPES), requestedType) >= 0) {\n if (requestedType === \"image/tiff\") {\n return qq.supportedFeatures.tiffPreviews ? requestedType : defaultType;\n }\n\n return requestedType;\n }\n\n return defaultType;\n },\n\n // Get a file name for a generated scaled file record, based on the provided scaled image description\n _getName: function(originalName, scaledVersionProperties) {\n \"use strict\";\n\n var startOfExt = originalName.lastIndexOf(\".\"),\n versionType = scaledVersionProperties.type || \"image/png\",\n referenceType = scaledVersionProperties.refType,\n scaledName = \"\",\n scaledExt = qq.getExtension(originalName),\n nameAppendage = \"\";\n\n if (scaledVersionProperties.name && scaledVersionProperties.name.trim().length) {\n nameAppendage = \" (\" + scaledVersionProperties.name + \")\";\n }\n\n if (startOfExt >= 0) {\n scaledName = originalName.substr(0, startOfExt);\n\n if (referenceType !== versionType) {\n scaledExt = versionType.split(\"/\")[1];\n }\n\n scaledName += nameAppendage + \".\" + scaledExt;\n }\n else {\n scaledName = originalName + nameAppendage;\n }\n\n return scaledName;\n },\n\n // We want the smallest scaled file to be uploaded first\n _getSortedSizes: function(sizes) {\n \"use strict\";\n\n sizes = qq.extend([], sizes);\n\n return sizes.sort(function(a, b) {\n if (a.maxSize > b.maxSize) {\n return 1;\n }\n if (a.maxSize < b.maxSize) {\n return -1;\n }\n return 0;\n });\n },\n\n _generateScaledImage: function(spec, sourceFile) {\n \"use strict\";\n\n var self = this,\n customResizeFunction = spec.customResizeFunction,\n log = spec.log,\n maxSize = spec.maxSize,\n orient = spec.orient,\n type = spec.type,\n quality = spec.quality,\n failedText = spec.failedText,\n includeExif = spec.includeExif && sourceFile.type === \"image/jpeg\" && type === \"image/jpeg\",\n scalingEffort = new qq.Promise(),\n imageGenerator = new qq.ImageGenerator(log),\n canvas = document.createElement(\"canvas\");\n\n log(\"Attempting to generate scaled version for \" + sourceFile.name);\n\n imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {\n var scaledImageDataUri = canvas.toDataURL(type, quality),\n signalSuccess = function() {\n log(\"Success generating scaled version for \" + sourceFile.name);\n var blob = qq.dataUriToBlob(scaledImageDataUri);\n scalingEffort.success(blob);\n };\n\n if (includeExif) {\n self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) {\n scaledImageDataUri = scaledImageDataUriWithExif;\n signalSuccess();\n },\n function() {\n log(\"Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.\", \"error\");\n signalSuccess();\n });\n }\n else {\n signalSuccess();\n }\n }, function() {\n log(\"Failed attempt to generate scaled version for \" + sourceFile.name, \"error\");\n scalingEffort.failure(failedText);\n });\n\n return scalingEffort;\n },\n\n // Attempt to insert the original image's EXIF header into a scaled version.\n _insertExifHeader: function(originalImage, scaledImageDataUri, log) {\n \"use strict\";\n\n var reader = new FileReader(),\n insertionEffort = new qq.Promise(),\n originalImageDataUri = \"\";\n\n reader.onload = function() {\n originalImageDataUri = reader.result;\n insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri));\n };\n\n reader.onerror = function() {\n log(\"Problem reading \" + originalImage.name + \" during attempt to transfer EXIF data to scaled version.\", \"error\");\n insertionEffort.failure();\n };\n\n reader.readAsDataURL(originalImage);\n\n return insertionEffort;\n },\n\n _dataUriToBlob: function(dataUri) {\n \"use strict\";\n\n var byteString, mimeString, arrayBuffer, intArray;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return this._createBlob(arrayBuffer, mimeString);\n },\n\n _createBlob: function(data, mime) {\n \"use strict\";\n\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n }\n});\n","//Based on MinifyJpeg\n//http://elicon.blog57.fc2.com/blog-entry-206.html\n\nqq.ExifRestorer = (function()\n{\n \n\tvar ExifRestorer = {};\n\t \n ExifRestorer.KEY_STR = \"ABCDEFGHIJKLMNOP\" +\n \"QRSTUVWXYZabcdef\" +\n \"ghijklmnopqrstuv\" +\n \"wxyz0123456789+/\" +\n \"=\";\n\n ExifRestorer.encode64 = function(input)\n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0;\n\n do {\n chr1 = input[i++];\n chr2 = input[i++];\n chr3 = input[i++];\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output +\n this.KEY_STR.charAt(enc1) +\n this.KEY_STR.charAt(enc2) +\n this.KEY_STR.charAt(enc3) +\n this.KEY_STR.charAt(enc4);\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n } while (i < input.length);\n\n return output;\n };\n \n ExifRestorer.restore = function(origFileBase64, resizedFileBase64)\n {\n var expectedBase64Header = \"data:image/jpeg;base64,\";\n\n if (!origFileBase64.match(expectedBase64Header))\n {\n \treturn resizedFileBase64;\n } \n \n var rawImage = this.decode64(origFileBase64.replace(expectedBase64Header, \"\"));\n var segments = this.slice2Segments(rawImage);\n \n var image = this.exifManipulation(resizedFileBase64, segments);\n \n return expectedBase64Header + this.encode64(image);\n \n };\n\n\n ExifRestorer.exifManipulation = function(resizedFileBase64, segments)\n {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray),\n aBuffer = new Uint8Array(newImageArray);\n\n return aBuffer;\n };\n\n\n ExifRestorer.getExifArray = function(segments)\n {\n var seg;\n for (var x = 0; x < segments.length; x++)\n {\n seg = segments[x];\n if (seg[0] == 255 & seg[1] == 225) //(ff e1)\n {\n return seg;\n }\n }\n return [];\n };\n\n\n ExifRestorer.insertExif = function(resizedFileBase64, exifArray)\n {\n var imageData = resizedFileBase64.replace(\"data:image/jpeg;base64,\", \"\"),\n buf = this.decode64(imageData),\n separatePoint = buf.indexOf(255,3),\n mae = buf.slice(0, separatePoint),\n ato = buf.slice(separatePoint),\n array = mae;\n\n array = array.concat(exifArray);\n array = array.concat(ato);\n return array;\n };\n\n\n \n ExifRestorer.slice2Segments = function(rawImageArray)\n {\n var head = 0,\n segments = [];\n\n while (1)\n {\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218){break;}\n if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216)\n {\n head += 2;\n }\n else\n {\n var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],\n endPoint = head + length + 2,\n seg = rawImageArray.slice(head, endPoint);\n segments.push(seg);\n head = endPoint;\n }\n if (head > rawImageArray.length){break;}\n }\n\n return segments;\n };\n\n\n \n ExifRestorer.decode64 = function(input) \n {\n var output = \"\",\n chr1, chr2, chr3 = \"\",\n enc1, enc2, enc3, enc4 = \"\",\n i = 0,\n buf = [];\n\n // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n var base64test = /[^A-Za-z0-9\\+\\/\\=]/g;\n if (base64test.exec(input)) {\n throw new Error(\"There were invalid base64 characters in the input text. \" +\n \"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\");\n }\n input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n do {\n enc1 = this.KEY_STR.indexOf(input.charAt(i++));\n enc2 = this.KEY_STR.indexOf(input.charAt(i++));\n enc3 = this.KEY_STR.indexOf(input.charAt(i++));\n enc4 = this.KEY_STR.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n\n buf.push(chr1);\n\n if (enc3 != 64) {\n buf.push(chr2);\n }\n if (enc4 != 64) {\n buf.push(chr3);\n }\n\n chr1 = chr2 = chr3 = \"\";\n enc1 = enc2 = enc3 = enc4 = \"\";\n\n } while (i < input.length);\n\n return buf;\n };\n\n \n return ExifRestorer;\n})();\n","/* globals qq */\n/**\n * Keeps a running tally of total upload progress for a batch of files.\n *\n * @param callback Invoked when total progress changes, passing calculated total loaded & total size values.\n * @param getSize Function that returns the size of a file given its ID\n * @constructor\n */\nqq.TotalProgress = function(callback, getSize) {\n \"use strict\";\n\n var perFileProgress = {},\n totalLoaded = 0,\n totalSize = 0,\n\n lastLoadedSent = -1,\n lastTotalSent = -1,\n callbackProxy = function(loaded, total) {\n if (loaded !== lastLoadedSent || total !== lastTotalSent) {\n callback(loaded, total);\n }\n\n lastLoadedSent = loaded;\n lastTotalSent = total;\n },\n\n /**\n * @param failed Array of file IDs that have failed\n * @param retryable Array of file IDs that are retryable\n * @returns true if none of the failed files are eligible for retry\n */\n noRetryableFiles = function(failed, retryable) {\n var none = true;\n\n qq.each(failed, function(idx, failedId) {\n if (qq.indexOf(retryable, failedId) >= 0) {\n none = false;\n return false;\n }\n });\n\n return none;\n },\n\n onCancel = function(id) {\n updateTotalProgress(id, -1, -1);\n delete perFileProgress[id];\n },\n\n onAllComplete = function(successful, failed, retryable) {\n if (failed.length === 0 || noRetryableFiles(failed, retryable)) {\n callbackProxy(totalSize, totalSize);\n this.reset();\n }\n },\n\n onNew = function(id) {\n var size = getSize(id);\n\n // We might not know the size yet, such as for blob proxies\n if (size > 0) {\n updateTotalProgress(id, 0, size);\n perFileProgress[id] = {loaded: 0, total: size};\n }\n },\n\n /**\n * Invokes the callback with the current total progress of all files in the batch. Called whenever it may\n * be appropriate to re-calculate and disseminate this data.\n *\n * @param id ID of a file that has changed in some important way\n * @param newLoaded New loaded value for this file. -1 if this value should no longer be part of calculations\n * @param newTotal New total size of the file. -1 if this value should no longer be part of calculations\n */\n updateTotalProgress = function(id, newLoaded, newTotal) {\n var oldLoaded = perFileProgress[id] ? perFileProgress[id].loaded : 0,\n oldTotal = perFileProgress[id] ? perFileProgress[id].total : 0;\n\n if (newLoaded === -1 && newTotal === -1) {\n totalLoaded -= oldLoaded;\n totalSize -= oldTotal;\n }\n else {\n if (newLoaded) {\n totalLoaded += newLoaded - oldLoaded;\n }\n if (newTotal) {\n totalSize += newTotal - oldTotal;\n }\n }\n\n callbackProxy(totalLoaded, totalSize);\n };\n\n qq.extend(this, {\n // Called when a batch of files has completed uploading.\n onAllComplete: onAllComplete,\n\n // Called when the status of a file has changed.\n onStatusChange: function(id, oldStatus, newStatus) {\n if (newStatus === qq.status.CANCELED || newStatus === qq.status.REJECTED) {\n onCancel(id);\n }\n else if (newStatus === qq.status.SUBMITTING) {\n onNew(id);\n }\n },\n\n // Called whenever the upload progress of an individual file has changed.\n onIndividualProgress: function(id, loaded, total) {\n updateTotalProgress(id, loaded, total);\n perFileProgress[id] = {loaded: loaded, total: total};\n },\n\n // Called whenever the total size of a file has changed, such as when the size of a generated blob is known.\n onNewSize: function(id) {\n onNew(id);\n },\n\n reset: function() {\n perFileProgress = {};\n totalLoaded = 0;\n totalSize = 0;\n }\n });\n};\n","/*globals qq*/\nqq.PasteSupport = function(o) {\n \"use strict\";\n\n var options, detachPasteHandler;\n\n options = {\n targetElement: null,\n callbacks: {\n log: function(message, level) {},\n pasteReceived: function(blob) {}\n }\n };\n\n function isImage(item) {\n return item.type &&\n item.type.indexOf(\"image/\") === 0;\n }\n\n function registerPasteHandler() {\n detachPasteHandler = qq(options.targetElement).attach(\"paste\", function(event) {\n var clipboardData = event.clipboardData;\n\n if (clipboardData) {\n qq.each(clipboardData.items, function(idx, item) {\n if (isImage(item)) {\n var blob = item.getAsFile();\n options.callbacks.pasteReceived(blob);\n }\n });\n }\n });\n }\n\n function unregisterPasteHandler() {\n if (detachPasteHandler) {\n detachPasteHandler();\n }\n }\n\n qq.extend(options, o);\n registerPasteHandler();\n\n qq.extend(this, {\n reset: function() {\n unregisterPasteHandler();\n }\n });\n};\n","/* globals qq */\n/**\n * Module that handles support for existing forms.\n *\n * @param options Options passed from the integrator-supplied options related to form support.\n * @param startUpload Callback to invoke when files \"stored\" should be uploaded.\n * @param log Proxy for the logger\n * @constructor\n */\nqq.FormSupport = function(options, startUpload, log) {\n \"use strict\";\n var self = this,\n interceptSubmit = options.interceptSubmit,\n formEl = options.element,\n autoUpload = options.autoUpload;\n\n // Available on the public API associated with this module.\n qq.extend(this, {\n // To be used by the caller to determine if the endpoint will be determined by some processing\n // that occurs in this module, such as if the form has an action attribute.\n // Ignore if `attachToForm === false`.\n newEndpoint: null,\n\n // To be used by the caller to determine if auto uploading should be allowed.\n // Ignore if `attachToForm === false`.\n newAutoUpload: autoUpload,\n\n // true if a form was detected and is being tracked by this module\n attachedToForm: false,\n\n // Returns an object with names and values for all valid form elements associated with the attached form.\n getFormInputsAsObject: function() {\n /* jshint eqnull:true */\n if (formEl == null) {\n return null;\n }\n\n return self._form2Obj(formEl);\n }\n });\n\n // If the form contains an action attribute, this should be the new upload endpoint.\n function determineNewEndpoint(formEl) {\n if (formEl.getAttribute(\"action\")) {\n self.newEndpoint = formEl.getAttribute(\"action\");\n }\n }\n\n // Return true only if the form is valid, or if we cannot make this determination.\n // If the form is invalid, ensure invalid field(s) are highlighted in the UI.\n function validateForm(formEl, nativeSubmit) {\n if (formEl.checkValidity && !formEl.checkValidity()) {\n log(\"Form did not pass validation checks - will not upload.\", \"error\");\n nativeSubmit();\n }\n else {\n return true;\n }\n }\n\n // Intercept form submit attempts, unless the integrator has told us not to do this.\n function maybeUploadOnSubmit(formEl) {\n var nativeSubmit = formEl.submit;\n\n // Intercept and squelch submit events.\n qq(formEl).attach(\"submit\", function(event) {\n event = event || window.event;\n\n if (event.preventDefault) {\n event.preventDefault();\n }\n else {\n event.returnValue = false;\n }\n\n validateForm(formEl, nativeSubmit) && startUpload();\n });\n\n // The form's `submit()` function may be called instead (i.e. via jQuery.submit()).\n // Intercept that too.\n formEl.submit = function() {\n validateForm(formEl, nativeSubmit) && startUpload();\n };\n }\n\n // If the element value passed from the uploader is a string, assume it is an element ID - select it.\n // The rest of the code in this module depends on this being an HTMLElement.\n function determineFormEl(formEl) {\n if (formEl) {\n if (qq.isString(formEl)) {\n formEl = document.getElementById(formEl);\n }\n\n if (formEl) {\n log(\"Attaching to form element.\");\n determineNewEndpoint(formEl);\n interceptSubmit && maybeUploadOnSubmit(formEl);\n }\n }\n\n return formEl;\n }\n\n formEl = determineFormEl(formEl);\n this.attachedToForm = !!formEl;\n};\n\nqq.extend(qq.FormSupport.prototype, {\n // Converts all relevant form fields to key/value pairs. This is meant to mimic the data a browser will\n // construct from a given form when the form is submitted.\n _form2Obj: function(form) {\n \"use strict\";\n var obj = {},\n notIrrelevantType = function(type) {\n var irrelevantTypes = [\n \"button\",\n \"image\",\n \"reset\",\n \"submit\"\n ];\n\n return qq.indexOf(irrelevantTypes, type.toLowerCase()) < 0;\n },\n radioOrCheckbox = function(type) {\n return qq.indexOf([\"checkbox\", \"radio\"], type.toLowerCase()) >= 0;\n },\n ignoreValue = function(el) {\n if (radioOrCheckbox(el.type) && !el.checked) {\n return true;\n }\n\n return el.disabled && el.type.toLowerCase() !== \"hidden\";\n },\n selectValue = function(select) {\n var value = null;\n\n qq.each(qq(select).children(), function(idx, child) {\n if (child.tagName.toLowerCase() === \"option\" && child.selected) {\n value = child.value;\n return false;\n }\n });\n\n return value;\n };\n\n qq.each(form.elements, function(idx, el) {\n if ((qq.isInput(el, true) || el.tagName.toLowerCase() === \"textarea\") &&\n notIrrelevantType(el.type) &&\n !ignoreValue(el)) {\n\n obj[el.name] = el.value;\n }\n else if (el.tagName.toLowerCase() === \"select\" && !ignoreValue(el)) {\n var value = selectValue(el);\n\n if (value !== null) {\n obj[el.name] = value;\n }\n }\n });\n\n return obj;\n }\n});\n","/*globals qq*/\n/**\n * Upload handler used that assumes the current user agent does not have any support for the\n * File API, and, therefore, makes use of iframes and forms to submit the files directly to\n * a generic server.\n *\n * @param options Options passed from the base handler\n * @param proxy Callbacks & methods used to query for or push out data/changes\n */\nqq.traditional = qq.traditional || {};\nqq.traditional.FormUploadHandler = function(options, proxy) {\n \"use strict\";\n\n var handler = this,\n getName = proxy.getName,\n getUuid = proxy.getUuid,\n log = proxy.log;\n\n /**\n * Returns json object received by iframe from server.\n */\n function getIframeContentJson(id, iframe) {\n /*jshint evil: true*/\n\n var response, doc, innerHtml;\n\n //IE may throw an \"access is denied\" error when attempting to access contentDocument on the iframe in some cases\n try {\n // iframe.contentWindow.document - for IE<7\n doc = iframe.contentDocument || iframe.contentWindow.document;\n innerHtml = doc.body.innerHTML;\n\n log(\"converting iframe's innerHTML to JSON\");\n log(\"innerHTML = \" + innerHtml);\n //plain text response may be wrapped in tag\n if (innerHtml && innerHtml.match(/^ 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.firefox()) {\n return !e.relatedTarget;\n }\n\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n e.preventDefault();\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n // dt.types.contains check is for firefox\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains(\"Files\")));\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n};\n","/*globals qq */\n/**\n * Defines the public API for FineUploader mode.\n */\n(function() {\n \"use strict\";\n\n qq.uiPublicApi = {\n addInitialFiles: function(cannedFileList) {\n this._parent.prototype.addInitialFiles.apply(this, arguments);\n this._templating.addCacheToDom();\n },\n\n clearStoredFiles: function() {\n this._parent.prototype.clearStoredFiles.apply(this, arguments);\n this._templating.clearFiles();\n },\n\n addExtraDropzone: function(element) {\n this._dnd && this._dnd.setupExtraDropzone(element);\n },\n\n removeExtraDropzone: function(element) {\n if (this._dnd) {\n return this._dnd.removeDropzone(element);\n }\n },\n\n getItemByFileId: function(id) {\n if (!this._templating.isHiddenForever(id)) {\n return this._templating.getFileContainer(id);\n }\n },\n\n reset: function() {\n this._parent.prototype.reset.apply(this, arguments);\n this._templating.reset();\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n if (this._dnd) {\n this._dnd.dispose();\n this._dnd = this._setupDragAndDrop();\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n\n this._setupClickAndEditEventHandlers();\n },\n\n setName: function(id, newName) {\n var formattedFilename = this._options.formatFileName(newName);\n\n this._parent.prototype.setName.apply(this, arguments);\n this._templating.updateFilename(id, formattedFilename);\n },\n\n pauseUpload: function(id) {\n var paused = this._parent.prototype.pauseUpload.apply(this, arguments);\n\n paused && this._templating.uploadPaused(id);\n return paused;\n },\n\n continueUpload: function(id) {\n var continued = this._parent.prototype.continueUpload.apply(this, arguments);\n\n continued && this._templating.uploadContinued(id);\n return continued;\n },\n\n getId: function(fileContainerOrChildEl) {\n return this._templating.getFileId(fileContainerOrChildEl);\n },\n\n getDropTarget: function(fileId) {\n var file = this.getFile(fileId);\n\n return file.qqDropTarget;\n }\n };\n\n /**\n * Defines the private (internal) API for FineUploader mode.\n */\n qq.uiPrivateApi = {\n _getButton: function(buttonId) {\n var button = this._parent.prototype._getButton.apply(this, arguments);\n\n if (!button) {\n if (buttonId === this._defaultButtonId) {\n button = this._templating.getButton();\n }\n }\n\n return button;\n },\n\n _removeFileItem: function(fileId) {\n this._templating.removeFile(fileId);\n },\n\n _setupClickAndEditEventHandlers: function() {\n this._fileButtonsClickHandler = qq.FileButtonsClickHandler && this._bindFileButtonsClickEvent();\n\n // A better approach would be to check specifically for focusin event support by querying the DOM API,\n // but the DOMFocusIn event is not exposed as a property, so we have to resort to UA string sniffing.\n this._focusinEventSupported = !qq.firefox();\n\n if (this._isEditFilenameEnabled())\n {\n this._filenameClickHandler = this._bindFilenameClickEvent();\n this._filenameInputFocusInHandler = this._bindFilenameInputFocusInEvent();\n this._filenameInputFocusHandler = this._bindFilenameInputFocusEvent();\n }\n },\n\n _setupDragAndDrop: function() {\n var self = this,\n dropZoneElements = this._options.dragAndDrop.extraDropzones,\n templating = this._templating,\n defaultDropZone = templating.getDropZone();\n\n defaultDropZone && dropZoneElements.push(defaultDropZone);\n\n return new qq.DragAndDrop({\n dropZoneElements: dropZoneElements,\n allowMultipleItems: this._options.multiple,\n classes: {\n dropActive: this._options.classes.dropActive\n },\n callbacks: {\n processingDroppedFiles: function() {\n templating.showDropProcessing();\n },\n processingDroppedFilesComplete: function(files, targetEl) {\n templating.hideDropProcessing();\n\n qq.each(files, function(idx, file) {\n file.qqDropTarget = targetEl;\n });\n\n if (files.length) {\n self.addFiles(files, null, null);\n }\n },\n dropError: function(code, errorData) {\n self._itemError(code, errorData);\n },\n dropLog: function(message, level) {\n self.log(message, level);\n }\n }\n });\n },\n\n _bindFileButtonsClickEvent: function() {\n var self = this;\n\n return new qq.FileButtonsClickHandler({\n templating: this._templating,\n\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n\n onDeleteFile: function(fileId) {\n self.deleteFile(fileId);\n },\n\n onCancel: function(fileId) {\n self.cancel(fileId);\n },\n\n onRetry: function(fileId) {\n self.retry(fileId);\n },\n\n onPause: function(fileId) {\n self.pauseUpload(fileId);\n },\n\n onContinue: function(fileId) {\n self.continueUpload(fileId);\n },\n\n onGetName: function(fileId) {\n return self.getName(fileId);\n }\n });\n },\n\n _isEditFilenameEnabled: function() {\n /*jshint -W014 */\n return this._templating.isEditFilenamePossible()\n && !this._options.autoUpload\n && qq.FilenameClickHandler\n && qq.FilenameInputFocusHandler\n && qq.FilenameInputFocusHandler;\n },\n\n _filenameEditHandler: function() {\n var self = this,\n templating = this._templating;\n\n return {\n templating: templating,\n log: function(message, lvl) {\n self.log(message, lvl);\n },\n onGetUploadStatus: function(fileId) {\n return self.getUploads({id: fileId}).status;\n },\n onGetName: function(fileId) {\n return self.getName(fileId);\n },\n onSetName: function(id, newName) {\n self.setName(id, newName);\n },\n onEditingStatusChange: function(id, isEditing) {\n var qqInput = qq(templating.getEditInput(id)),\n qqFileContainer = qq(templating.getFileContainer(id));\n\n if (isEditing) {\n qqInput.addClass(\"qq-editing\");\n templating.hideFilename(id);\n templating.hideEditIcon(id);\n }\n else {\n qqInput.removeClass(\"qq-editing\");\n templating.showFilename(id);\n templating.showEditIcon(id);\n }\n\n // Force IE8 and older to repaint\n qqFileContainer.addClass(\"qq-temp\").removeClass(\"qq-temp\");\n }\n };\n },\n\n _onUploadStatusChange: function(id, oldStatus, newStatus) {\n this._parent.prototype._onUploadStatusChange.apply(this, arguments);\n\n if (this._isEditFilenameEnabled()) {\n // Status for a file exists before it has been added to the DOM, so we must be careful here.\n if (this._templating.getFileContainer(id) && newStatus !== qq.status.SUBMITTED) {\n this._templating.markFilenameEditable(id);\n this._templating.hideEditIcon(id);\n }\n }\n\n if (oldStatus === qq.status.UPLOAD_RETRYING && newStatus === qq.status.UPLOADING) {\n this._templating.hideRetry(id);\n this._templating.setStatusText(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.retrying);\n }\n else if (newStatus === qq.status.UPLOAD_FAILED) {\n this._templating.hidePause(id);\n }\n },\n\n _bindFilenameInputFocusInEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusInHandler(spec);\n },\n\n _bindFilenameInputFocusEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameInputFocusHandler(spec);\n },\n\n _bindFilenameClickEvent: function() {\n var spec = qq.extend({}, this._filenameEditHandler());\n\n return new qq.FilenameClickHandler(spec);\n },\n\n _storeForLater: function(id) {\n this._parent.prototype._storeForLater.apply(this, arguments);\n this._templating.hideSpinner(id);\n },\n\n _onAllComplete: function(successful, failed) {\n this._parent.prototype._onAllComplete.apply(this, arguments);\n this._templating.resetTotalProgress();\n },\n\n _onSubmit: function(id, name) {\n var file = this.getFile(id);\n\n if (file && file.qqPath && this._options.dragAndDrop.reportDirectoryPaths) {\n this._paramsStore.addReadOnly(id, {\n qqpath: file.qqPath\n });\n }\n\n this._parent.prototype._onSubmit.apply(this, arguments);\n this._addToList(id, name);\n },\n\n // The file item has been added to the DOM.\n _onSubmitted: function(id) {\n // If the edit filename feature is enabled, mark the filename element as \"editable\" and the associated edit icon\n if (this._isEditFilenameEnabled()) {\n this._templating.markFilenameEditable(id);\n this._templating.showEditIcon(id);\n\n // If the focusin event is not supported, we must add a focus handler to the newly create edit filename text input\n if (!this._focusinEventSupported) {\n this._filenameInputFocusHandler.addHandler(this._templating.getEditInput(id));\n }\n }\n },\n\n // Update the progress bar & percentage as the file is uploaded\n _onProgress: function(id, name, loaded, total) {\n this._parent.prototype._onProgress.apply(this, arguments);\n\n this._templating.updateProgress(id, loaded, total);\n\n if (total === 0 || Math.round(loaded / total * 100) === 100) {\n this._templating.hideCancel(id);\n this._templating.hidePause(id);\n this._templating.hideProgress(id);\n this._templating.setStatusText(id, this._options.text.waitingForResponse);\n\n // If ~last byte was sent, display total file size\n this._displayFileSize(id);\n }\n else {\n // If still uploading, display percentage - total size is actually the total request(s) size\n this._displayFileSize(id, loaded, total);\n }\n },\n\n _onTotalProgress: function(loaded, total) {\n this._parent.prototype._onTotalProgress.apply(this, arguments);\n this._templating.updateTotalProgress(loaded, total);\n },\n\n _onComplete: function(id, name, result, xhr) {\n var parentRetVal = this._parent.prototype._onComplete.apply(this, arguments),\n templating = this._templating,\n fileContainer = templating.getFileContainer(id),\n self = this;\n\n function completeUpload(result) {\n // If this file is not represented in the templating module, perhaps it was hidden intentionally.\n // If so, don't perform any UI-related tasks related to this file.\n if (!fileContainer) {\n return;\n }\n\n templating.setStatusText(id);\n\n qq(fileContainer).removeClass(self._classes.retrying);\n templating.hideProgress(id);\n\n if (self.getUploads({id: id}).status !== qq.status.UPLOAD_FAILED) {\n templating.hideCancel(id);\n }\n templating.hideSpinner(id);\n\n if (result.success) {\n self._markFileAsSuccessful(id);\n }\n else {\n qq(fileContainer).addClass(self._classes.fail);\n templating.showCancel(id);\n\n if (templating.isRetryPossible() && !self._preventRetries[id]) {\n qq(fileContainer).addClass(self._classes.retryable);\n templating.showRetry(id);\n }\n self._controlFailureTextDisplay(id, result);\n }\n }\n\n // The parent may need to perform some async operation before we can accurately determine the status of the upload.\n if (parentRetVal instanceof qq.Promise) {\n parentRetVal.done(function(newResult) {\n completeUpload(newResult);\n });\n\n }\n else {\n completeUpload(result);\n }\n\n return parentRetVal;\n },\n\n _markFileAsSuccessful: function(id) {\n var templating = this._templating;\n\n if (this._isDeletePossible()) {\n templating.showDeleteButton(id);\n }\n\n qq(templating.getFileContainer(id)).addClass(this._classes.success);\n\n this._maybeUpdateThumbnail(id);\n },\n\n _onUploadPrep: function(id) {\n this._parent.prototype._onUploadPrep.apply(this, arguments);\n this._templating.showSpinner(id);\n },\n\n _onUpload: function(id, name) {\n var parentRetVal = this._parent.prototype._onUpload.apply(this, arguments);\n\n this._templating.showSpinner(id);\n\n return parentRetVal;\n },\n\n _onUploadChunk: function(id, chunkData) {\n this._parent.prototype._onUploadChunk.apply(this, arguments);\n\n // Only display the pause button if we have finished uploading at least one chunk\n // & this file can be resumed\n if (chunkData.partIndex > 0 && this._handler.isResumable(id)) {\n this._templating.allowPause(id);\n }\n },\n\n _onCancel: function(id, name) {\n this._parent.prototype._onCancel.apply(this, arguments);\n this._removeFileItem(id);\n\n if (this._getNotFinished() === 0) {\n this._templating.resetTotalProgress();\n }\n },\n\n _onBeforeAutoRetry: function(id) {\n var retryNumForDisplay, maxAuto, retryNote;\n\n this._parent.prototype._onBeforeAutoRetry.apply(this, arguments);\n\n this._showCancelLink(id);\n\n if (this._options.retry.showAutoRetryNote) {\n retryNumForDisplay = this._autoRetries[id];\n maxAuto = this._options.retry.maxAutoAttempts;\n\n retryNote = this._options.retry.autoRetryNote.replace(/\\{retryNum\\}/g, retryNumForDisplay);\n retryNote = retryNote.replace(/\\{maxAuto\\}/g, maxAuto);\n\n this._templating.setStatusText(id, retryNote);\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retrying);\n }\n },\n\n //return false if we should not attempt the requested retry\n _onBeforeManualRetry: function(id) {\n if (this._parent.prototype._onBeforeManualRetry.apply(this, arguments)) {\n this._templating.resetProgress(id);\n qq(this._templating.getFileContainer(id)).removeClass(this._classes.fail);\n this._templating.setStatusText(id);\n this._templating.showSpinner(id);\n this._showCancelLink(id);\n return true;\n }\n else {\n qq(this._templating.getFileContainer(id)).addClass(this._classes.retryable);\n this._templating.showRetry(id);\n return false;\n }\n },\n\n _onSubmitDelete: function(id) {\n var onSuccessCallback = qq.bind(this._onSubmitDeleteSuccess, this);\n\n this._parent.prototype._onSubmitDelete.call(this, id, onSuccessCallback);\n },\n\n _onSubmitDeleteSuccess: function(id, uuid, additionalMandatedParams) {\n if (this._options.deleteFile.forceConfirm) {\n this._showDeleteConfirm.apply(this, arguments);\n }\n else {\n this._sendDeleteRequest.apply(this, arguments);\n }\n },\n\n _onDeleteComplete: function(id, xhr, isError) {\n this._parent.prototype._onDeleteComplete.apply(this, arguments);\n\n this._templating.hideSpinner(id);\n\n if (isError) {\n this._templating.setStatusText(id, this._options.deleteFile.deletingFailedText);\n this._templating.showDeleteButton(id);\n }\n else {\n this._removeFileItem(id);\n }\n },\n\n _sendDeleteRequest: function(id, uuid, additionalMandatedParams) {\n this._templating.hideDeleteButton(id);\n this._templating.showSpinner(id);\n this._templating.setStatusText(id, this._options.deleteFile.deletingStatusText);\n this._deleteHandler.sendDelete.apply(this, arguments);\n },\n\n _showDeleteConfirm: function(id, uuid, mandatedParams) {\n /*jshint -W004 */\n var fileName = this.getName(id),\n confirmMessage = this._options.deleteFile.confirmMessage.replace(/\\{filename\\}/g, fileName),\n uuid = this.getUuid(id),\n deleteRequestArgs = arguments,\n self = this,\n retVal;\n\n retVal = this._options.showConfirm(confirmMessage);\n\n if (qq.isGenericPromise(retVal)) {\n retVal.then(function() {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n });\n }\n else if (retVal !== false) {\n self._sendDeleteRequest.apply(self, deleteRequestArgs);\n }\n },\n\n _addToList: function(id, name, canned) {\n var prependData,\n prependIndex = 0,\n dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled,\n record;\n\n if (this._options.display.prependFiles) {\n if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {\n prependIndex = this._filesInBatchAddedToUi - 1;\n }\n\n prependData = {\n index: prependIndex\n };\n }\n\n if (!canned) {\n if (this._options.disableCancelForFormUploads && !qq.supportedFeatures.ajaxUploading) {\n this._templating.disableCancel();\n }\n\n // Cancel all existing (previous) files and clear the list if this file is not part of\n // a scaled file group that has already been accepted, or if this file is not part of\n // a scaled file group at all.\n if (!this._options.multiple) {\n record = this.getUploads({id: id});\n\n this._handledProxyGroup = this._handledProxyGroup || record.proxyGroupId;\n\n if (record.proxyGroupId !== this._handledProxyGroup || !record.proxyGroupId) {\n this._handler.cancelAll();\n this._clearList();\n this._handledProxyGroup = null;\n }\n }\n }\n\n if (canned) {\n this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);\n }\n else {\n this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);\n this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);\n }\n\n this._filesInBatchAddedToUi += 1;\n\n if (canned ||\n (this._options.display.fileSizeOnSubmit && qq.supportedFeatures.ajaxUploading)) {\n\n this._displayFileSize(id);\n }\n },\n\n _clearList: function() {\n this._templating.clearFiles();\n this.clearStoredFiles();\n },\n\n _displayFileSize: function(id, loadedSize, totalSize) {\n var size = this.getSize(id),\n sizeForDisplay = this._formatSize(size);\n\n if (size >= 0) {\n if (loadedSize !== undefined && totalSize !== undefined) {\n sizeForDisplay = this._formatProgress(loadedSize, totalSize);\n }\n\n this._templating.updateSize(id, sizeForDisplay);\n }\n },\n\n _formatProgress: function(uploadedSize, totalSize) {\n var message = this._options.text.formatProgress;\n function r(name, replacement) { message = message.replace(name, replacement); }\n\n r(\"{percent}\", Math.round(uploadedSize / totalSize * 100));\n r(\"{total_size}\", this._formatSize(totalSize));\n return message;\n },\n\n _controlFailureTextDisplay: function(id, response) {\n var mode, responseProperty, failureReason;\n\n mode = this._options.failedUploadTextDisplay.mode;\n responseProperty = this._options.failedUploadTextDisplay.responseProperty;\n\n if (mode === \"custom\") {\n failureReason = response[responseProperty];\n if (!failureReason) {\n failureReason = this._options.text.failUpload;\n }\n\n this._templating.setStatusText(id, failureReason);\n\n if (this._options.failedUploadTextDisplay.enableTooltip) {\n this._showTooltip(id, failureReason);\n }\n }\n else if (mode === \"default\") {\n this._templating.setStatusText(id, this._options.text.failUpload);\n }\n else if (mode !== \"none\") {\n this.log(\"failedUploadTextDisplay.mode value of '\" + mode + \"' is not valid\", \"warn\");\n }\n },\n\n _showTooltip: function(id, text) {\n this._templating.getFileContainer(id).title = text;\n },\n\n _showCancelLink: function(id) {\n if (!this._options.disableCancelForFormUploads || qq.supportedFeatures.ajaxUploading) {\n this._templating.showCancel(id);\n }\n },\n\n _itemError: function(code, name, item) {\n var message = this._parent.prototype._itemError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _batchError: function(message) {\n this._parent.prototype._batchError.apply(this, arguments);\n this._options.showMessage(message);\n },\n\n _setupPastePrompt: function() {\n var self = this;\n\n this._options.callbacks.onPasteReceived = function() {\n var message = self._options.paste.namePromptMessage,\n defaultVal = self._options.paste.defaultName;\n\n return self._options.showPrompt(message, defaultVal);\n };\n },\n\n _fileOrBlobRejected: function(id, name) {\n this._totalFilesInBatch -= 1;\n this._parent.prototype._fileOrBlobRejected.apply(this, arguments);\n },\n\n _prepareItemsForUpload: function(items, params, endpoint) {\n this._totalFilesInBatch = items.length;\n this._filesInBatchAddedToUi = 0;\n this._parent.prototype._prepareItemsForUpload.apply(this, arguments);\n },\n\n _maybeUpdateThumbnail: function(fileId) {\n var thumbnailUrl = this._thumbnailUrls[fileId],\n fileStatus = this.getUploads({id: fileId}).status;\n\n if (fileStatus !== qq.status.DELETED &&\n (thumbnailUrl ||\n this._options.thumbnails.placeholders.waitUntilResponse ||\n !qq.supportedFeatures.imagePreviews)) {\n\n // This will replace the \"waiting\" placeholder with a \"preview not available\" placeholder\n // if called with a null thumbnailUrl.\n this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);\n }\n },\n\n _addCannedFile: function(sessionData) {\n var id = this._parent.prototype._addCannedFile.apply(this, arguments);\n\n this._addToList(id, this.getName(id), true);\n this._templating.hideSpinner(id);\n this._templating.hideCancel(id);\n this._markFileAsSuccessful(id);\n\n return id;\n },\n\n _setSize: function(id, newSize) {\n this._parent.prototype._setSize.apply(this, arguments);\n\n this._templating.updateSize(id, this._formatSize(newSize));\n },\n\n _sessionRequestComplete: function() {\n this._templating.addCacheToDom();\n this._parent.prototype._sessionRequestComplete.apply(this, arguments);\n }\n };\n}());\n","/*globals qq */\n/**\n * This defines FineUploader mode, which is a default UI w/ drag & drop uploading.\n */\nqq.FineUploader = function(o, namespace) {\n \"use strict\";\n\n var self = this;\n\n // By default this should inherit instance data from FineUploaderBasic, but this can be overridden\n // if the (internal) caller defines a different parent. The parent is also used by\n // the private and public API functions that need to delegate to a parent function.\n this._parent = namespace ? qq[namespace].FineUploaderBasic : qq.FineUploaderBasic;\n this._parent.apply(this, arguments);\n\n // Options provided by FineUploader mode\n qq.extend(this._options, {\n element: null,\n\n button: null,\n\n listElement: null,\n\n dragAndDrop: {\n extraDropzones: [],\n reportDirectoryPaths: false\n },\n\n text: {\n formatProgress: \"{percent}% of {total_size}\",\n failUpload: \"Upload failed\",\n waitingForResponse: \"Processing...\",\n paused: \"Paused\"\n },\n\n template: \"qq-template\",\n\n classes: {\n retrying: \"qq-upload-retrying\",\n retryable: \"qq-upload-retryable\",\n success: \"qq-upload-success\",\n fail: \"qq-upload-fail\",\n editable: \"qq-editable\",\n hide: \"qq-hide\",\n dropActive: \"qq-upload-drop-area-active\"\n },\n\n failedUploadTextDisplay: {\n mode: \"default\", //default, custom, or none\n responseProperty: \"error\",\n enableTooltip: true\n },\n\n messages: {\n tooManyFilesError: \"You may only drop one file\",\n unsupportedBrowser: \"Unrecoverable error - this browser does not permit file uploading of any kind.\"\n },\n\n retry: {\n showAutoRetryNote: true,\n autoRetryNote: \"Retrying {retryNum}/{maxAuto}...\"\n },\n\n deleteFile: {\n forceConfirm: false,\n confirmMessage: \"Are you sure you want to delete {filename}?\",\n deletingStatusText: \"Deleting...\",\n deletingFailedText: \"Delete failed\"\n\n },\n\n display: {\n fileSizeOnSubmit: false,\n prependFiles: false\n },\n\n paste: {\n promptForName: false,\n namePromptMessage: \"Please name this image\"\n },\n\n thumbnails: {\n customResizer: null,\n maxCount: 0,\n placeholders: {\n waitUntilResponse: false,\n notAvailablePath: null,\n waitingPath: null\n },\n timeBetweenThumbs: 750\n },\n\n scaling: {\n hideScaled: false\n },\n\n showMessage: function(message) {\n if (self._templating.hasDialog(\"alert\")) {\n return self._templating.showDialog(\"alert\", message);\n }\n else {\n setTimeout(function() {\n window.alert(message);\n }, 0);\n }\n },\n\n showConfirm: function(message) {\n if (self._templating.hasDialog(\"confirm\")) {\n return self._templating.showDialog(\"confirm\", message);\n }\n else {\n return window.confirm(message);\n }\n },\n\n showPrompt: function(message, defaultValue) {\n if (self._templating.hasDialog(\"prompt\")) {\n return self._templating.showDialog(\"prompt\", message, defaultValue);\n }\n else {\n return window.prompt(message, defaultValue);\n }\n }\n }, true);\n\n // Replace any default options with user defined ones\n qq.extend(this._options, o, true);\n\n this._templating = new qq.Templating({\n log: qq.bind(this.log, this),\n templateIdOrEl: this._options.template,\n containerEl: this._options.element,\n fileContainerEl: this._options.listElement,\n button: this._options.button,\n imageGenerator: this._imageGenerator,\n classes: {\n hide: this._options.classes.hide,\n editable: this._options.classes.editable\n },\n limits: {\n maxThumbs: this._options.thumbnails.maxCount,\n timeBetweenThumbs: this._options.thumbnails.timeBetweenThumbs\n },\n placeholders: {\n waitUntilUpdate: this._options.thumbnails.placeholders.waitUntilResponse,\n thumbnailNotAvailable: this._options.thumbnails.placeholders.notAvailablePath,\n waitingForThumbnail: this._options.thumbnails.placeholders.waitingPath\n },\n text: this._options.text\n });\n\n if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowserIos8Safari);\n }\n else if (!qq.supportedFeatures.uploading || (this._options.cors.expected && !qq.supportedFeatures.uploadCors)) {\n this._templating.renderFailure(this._options.messages.unsupportedBrowser);\n }\n else {\n this._wrapCallbacks();\n\n this._templating.render();\n\n this._classes = this._options.classes;\n\n if (!this._options.button && this._templating.getButton()) {\n this._defaultButtonId = this._createUploadButton({\n element: this._templating.getButton(),\n title: this._options.text.fileInputTitle\n }).getButtonId();\n }\n\n this._setupClickAndEditEventHandlers();\n\n if (qq.DragAndDrop && qq.supportedFeatures.fileDrop) {\n this._dnd = this._setupDragAndDrop();\n }\n\n if (this._options.paste.targetElement && this._options.paste.promptForName) {\n if (qq.PasteSupport) {\n this._setupPastePrompt();\n }\n else {\n this.log(\"Paste support module not found.\", \"error\");\n }\n }\n\n this._totalFilesInBatch = 0;\n this._filesInBatchAddedToUi = 0;\n }\n};\n\n// Inherit the base public & private API methods\nqq.extend(qq.FineUploader.prototype, qq.basePublicApi);\nqq.extend(qq.FineUploader.prototype, qq.basePrivateApi);\n\n// Add the FineUploader/default UI public & private UI methods, which may override some base methods.\nqq.extend(qq.FineUploader.prototype, qq.uiPublicApi);\nqq.extend(qq.FineUploader.prototype, qq.uiPrivateApi);\n","/* globals qq */\n/* jshint -W065 */\n/**\n * Module responsible for rendering all Fine Uploader UI templates. This module also asserts at least\n * a limited amount of control over the template elements after they are added to the DOM.\n * Wherever possible, this module asserts total control over template elements present in the DOM.\n *\n * @param spec Specification object used to control various templating behaviors\n * @constructor\n */\nqq.Templating = function(spec) {\n \"use strict\";\n\n var FILE_ID_ATTR = \"qq-file-id\",\n FILE_CLASS_PREFIX = \"qq-file-id-\",\n THUMBNAIL_MAX_SIZE_ATTR = \"qq-max-size\",\n THUMBNAIL_SERVER_SCALE_ATTR = \"qq-server-scale\",\n // This variable is duplicated in the DnD module since it can function as a standalone as well\n HIDE_DROPZONE_ATTR = \"qq-hide-dropzone\",\n DROPZPONE_TEXT_ATTR = \"qq-drop-area-text\",\n IN_PROGRESS_CLASS = \"qq-in-progress\",\n HIDDEN_FOREVER_CLASS = \"qq-hidden-forever\",\n fileBatch = {\n content: document.createDocumentFragment(),\n map: {}\n },\n isCancelDisabled = false,\n generatedThumbnails = 0,\n thumbnailQueueMonitorRunning = false,\n thumbGenerationQueue = [],\n thumbnailMaxSize = -1,\n options = {\n log: null,\n limits: {\n maxThumbs: 0,\n timeBetweenThumbs: 750\n },\n templateIdOrEl: \"qq-template\",\n containerEl: null,\n fileContainerEl: null,\n button: null,\n imageGenerator: null,\n classes: {\n hide: \"qq-hide\",\n editable: \"qq-editable\"\n },\n placeholders: {\n waitUntilUpdate: false,\n thumbnailNotAvailable: null,\n waitingForThumbnail: null\n },\n text: {\n paused: \"Paused\"\n }\n },\n selectorClasses = {\n button: \"qq-upload-button-selector\",\n alertDialog: \"qq-alert-dialog-selector\",\n dialogCancelButton: \"qq-cancel-button-selector\",\n confirmDialog: \"qq-confirm-dialog-selector\",\n dialogMessage: \"qq-dialog-message-selector\",\n dialogOkButton: \"qq-ok-button-selector\",\n promptDialog: \"qq-prompt-dialog-selector\",\n uploader: \"qq-uploader-selector\",\n drop: \"qq-upload-drop-area-selector\",\n list: \"qq-upload-list-selector\",\n progressBarContainer: \"qq-progress-bar-container-selector\",\n progressBar: \"qq-progress-bar-selector\",\n totalProgressBarContainer: \"qq-total-progress-bar-container-selector\",\n totalProgressBar: \"qq-total-progress-bar-selector\",\n file: \"qq-upload-file-selector\",\n spinner: \"qq-upload-spinner-selector\",\n size: \"qq-upload-size-selector\",\n cancel: \"qq-upload-cancel-selector\",\n pause: \"qq-upload-pause-selector\",\n continueButton: \"qq-upload-continue-selector\",\n deleteButton: \"qq-upload-delete-selector\",\n retry: \"qq-upload-retry-selector\",\n statusText: \"qq-upload-status-text-selector\",\n editFilenameInput: \"qq-edit-filename-selector\",\n editNameIcon: \"qq-edit-filename-icon-selector\",\n dropText: \"qq-upload-drop-area-text-selector\",\n dropProcessing: \"qq-drop-processing-selector\",\n dropProcessingSpinner: \"qq-drop-processing-spinner-selector\",\n thumbnail: \"qq-thumbnail-selector\"\n },\n previewGeneration = {},\n cachedThumbnailNotAvailableImg = new qq.Promise(),\n cachedWaitingForThumbnailImg = new qq.Promise(),\n log,\n isEditElementsExist,\n isRetryElementExist,\n templateHtml,\n container,\n fileList,\n showThumbnails,\n serverScale,\n\n // During initialization of the templating module we should cache any\n // placeholder images so we can quickly swap them into the file list on demand.\n // Any placeholder images that cannot be loaded/found are simply ignored.\n cacheThumbnailPlaceholders = function() {\n var notAvailableUrl = options.placeholders.thumbnailNotAvailable,\n waitingUrl = options.placeholders.waitingForThumbnail,\n spec = {\n maxSize: thumbnailMaxSize,\n scale: serverScale\n };\n\n if (showThumbnails) {\n if (notAvailableUrl) {\n options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedThumbnailNotAvailableImg.success(updatedImg);\n },\n function() {\n cachedThumbnailNotAvailableImg.failure();\n log(\"Problem loading 'not available' placeholder image at \" + notAvailableUrl, \"error\");\n }\n );\n }\n else {\n cachedThumbnailNotAvailableImg.failure();\n }\n\n if (waitingUrl) {\n options.imageGenerator.generate(waitingUrl, new Image(), spec).then(\n function(updatedImg) {\n cachedWaitingForThumbnailImg.success(updatedImg);\n },\n function() {\n cachedWaitingForThumbnailImg.failure();\n log(\"Problem loading 'waiting for thumbnail' placeholder image at \" + waitingUrl, \"error\");\n }\n );\n }\n else {\n cachedWaitingForThumbnailImg.failure();\n }\n }\n },\n\n // Displays a \"waiting for thumbnail\" type placeholder image\n // iff we were able to load it during initialization of the templating module.\n displayWaitingImg = function(thumbnail) {\n var waitingImgPlacement = new qq.Promise();\n\n cachedWaitingForThumbnailImg.then(function(img) {\n maybeScalePlaceholderViaCss(img, thumbnail);\n /* jshint eqnull:true */\n if (!thumbnail.src) {\n thumbnail.src = img.src;\n thumbnail.onload = function() {\n thumbnail.onload = null;\n show(thumbnail);\n waitingImgPlacement.success();\n };\n }\n else {\n waitingImgPlacement.success();\n }\n }, function() {\n // In some browsers (such as IE9 and older) an img w/out a src attribute\n // are displayed as \"broken\" images, so we should just hide the img tag\n // if we aren't going to display the \"waiting\" placeholder.\n hide(thumbnail);\n waitingImgPlacement.success();\n });\n\n return waitingImgPlacement;\n },\n\n generateNewPreview = function(id, blob, spec) {\n var thumbnail = getThumbnail(id);\n\n log(\"Generating new thumbnail for \" + id);\n blob.qqThumbnailId = id;\n\n return options.imageGenerator.generate(blob, thumbnail, spec).then(\n function() {\n generatedThumbnails++;\n show(thumbnail);\n previewGeneration[id].success();\n },\n function() {\n previewGeneration[id].failure();\n\n // Display the \"not available\" placeholder img only if we are\n // not expecting a thumbnail at a later point, such as in a server response.\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n }\n });\n },\n\n generateNextQueuedPreview = function() {\n if (thumbGenerationQueue.length) {\n thumbnailQueueMonitorRunning = true;\n\n var queuedThumbRequest = thumbGenerationQueue.shift();\n\n if (queuedThumbRequest.update) {\n processUpdateQueuedPreviewRequest(queuedThumbRequest);\n }\n else {\n processNewQueuedPreviewRequest(queuedThumbRequest);\n }\n }\n else {\n thumbnailQueueMonitorRunning = false;\n }\n },\n\n getCancel = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.cancel);\n },\n\n getContinue = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.continueButton);\n },\n\n getDialog = function(type) {\n return getTemplateEl(container, selectorClasses[type + \"Dialog\"]);\n },\n\n getDelete = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.deleteButton);\n },\n\n getDropProcessing = function() {\n return getTemplateEl(container, selectorClasses.dropProcessing);\n },\n\n getEditIcon = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editNameIcon);\n },\n\n getFile = function(id) {\n return fileBatch.map[id] || qq(fileList).getFirstByClass(FILE_CLASS_PREFIX + id);\n },\n\n getFilename = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.file);\n },\n\n getPause = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.pause);\n },\n\n getProgress = function(id) {\n /* jshint eqnull:true */\n // Total progress bar\n if (id == null) {\n return getTemplateEl(container, selectorClasses.totalProgressBarContainer) ||\n getTemplateEl(container, selectorClasses.totalProgressBar);\n }\n\n // Per-file progress bar\n return getTemplateEl(getFile(id), selectorClasses.progressBarContainer) ||\n getTemplateEl(getFile(id), selectorClasses.progressBar);\n },\n\n getRetry = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.retry);\n },\n\n getSize = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.size);\n },\n\n getSpinner = function(id) {\n return getTemplateEl(getFile(id), selectorClasses.spinner);\n },\n\n getTemplateEl = function(context, cssClass) {\n return context && qq(context).getFirstByClass(cssClass);\n },\n\n getThumbnail = function(id) {\n return showThumbnails && getTemplateEl(getFile(id), selectorClasses.thumbnail);\n },\n\n hide = function(el) {\n el && qq(el).addClass(options.classes.hide);\n },\n\n // Ensures a placeholder image does not exceed any max size specified\n // via `style` attribute properties iff was not used to scale\n // the placeholder AND the target doesn't already have these `style` attribute properties set.\n maybeScalePlaceholderViaCss = function(placeholder, thumbnail) {\n var maxWidth = placeholder.style.maxWidth,\n maxHeight = placeholder.style.maxHeight;\n\n if (maxHeight && maxWidth && !thumbnail.style.maxWidth && !thumbnail.style.maxHeight) {\n qq(thumbnail).css({\n maxWidth: maxWidth,\n maxHeight: maxHeight\n });\n }\n },\n\n // Displays a \"thumbnail not available\" type placeholder image\n // iff we were able to load this placeholder during initialization\n // of the templating module or after preview generation has failed.\n maybeSetDisplayNotAvailableImg = function(id, thumbnail) {\n var previewing = previewGeneration[id] || new qq.Promise().failure(),\n notAvailableImgPlacement = new qq.Promise();\n\n cachedThumbnailNotAvailableImg.then(function(img) {\n previewing.then(\n function() {\n notAvailableImgPlacement.success();\n },\n function() {\n maybeScalePlaceholderViaCss(img, thumbnail);\n\n thumbnail.onload = function() {\n thumbnail.onload = null;\n notAvailableImgPlacement.success();\n };\n\n thumbnail.src = img.src;\n show(thumbnail);\n }\n );\n });\n\n return notAvailableImgPlacement;\n },\n\n /**\n * Grabs the HTML from the script tag holding the template markup. This function will also adjust\n * some internally-tracked state variables based on the contents of the template.\n * The template is filtered so that irrelevant elements (such as the drop zone if DnD is not supported)\n * are omitted from the DOM. Useful errors will be thrown if the template cannot be parsed.\n *\n * @returns {{template: *, fileTemplate: *}} HTML for the top-level file items templates\n */\n parseAndGetTemplate = function() {\n var scriptEl,\n scriptHtml,\n fileListNode,\n tempTemplateEl,\n fileListHtml,\n defaultButton,\n dropArea,\n thumbnail,\n dropProcessing,\n dropTextEl,\n uploaderEl;\n\n log(\"Parsing template\");\n\n /*jshint -W116*/\n if (options.templateIdOrEl == null) {\n throw new Error(\"You MUST specify either a template element or ID!\");\n }\n\n // Grab the contents of the script tag holding the template.\n if (qq.isString(options.templateIdOrEl)) {\n scriptEl = document.getElementById(options.templateIdOrEl);\n\n if (scriptEl === null) {\n throw new Error(qq.format(\"Cannot find template script at ID '{}'!\", options.templateIdOrEl));\n }\n\n scriptHtml = scriptEl.innerHTML;\n }\n else {\n if (options.templateIdOrEl.innerHTML === undefined) {\n throw new Error(\"You have specified an invalid value for the template option! \" +\n \"It must be an ID or an Element.\");\n }\n\n scriptHtml = options.templateIdOrEl.innerHTML;\n }\n\n scriptHtml = qq.trimStr(scriptHtml);\n tempTemplateEl = document.createElement(\"div\");\n tempTemplateEl.appendChild(qq.toElement(scriptHtml));\n uploaderEl = qq(tempTemplateEl).getFirstByClass(selectorClasses.uploader);\n\n // Don't include the default template button in the DOM\n // if an alternate button container has been specified.\n if (options.button) {\n defaultButton = qq(tempTemplateEl).getFirstByClass(selectorClasses.button);\n if (defaultButton) {\n qq(defaultButton).remove();\n }\n }\n\n // Omit the drop processing element from the DOM if DnD is not supported by the UA,\n // or the drag and drop module is not found.\n // NOTE: We are consciously not removing the drop zone if the UA doesn't support DnD\n // to support layouts where the drop zone is also a container for visible elements,\n // such as the file list.\n if (!qq.DragAndDrop || !qq.supportedFeatures.fileDrop) {\n dropProcessing = qq(tempTemplateEl).getFirstByClass(selectorClasses.dropProcessing);\n if (dropProcessing) {\n qq(dropProcessing).remove();\n }\n }\n\n dropArea = qq(tempTemplateEl).getFirstByClass(selectorClasses.drop);\n\n // If DnD is not available then remove\n // it from the DOM as well.\n if (dropArea && !qq.DragAndDrop) {\n log(\"DnD module unavailable.\", \"info\");\n qq(dropArea).remove();\n }\n\n if (!qq.supportedFeatures.fileDrop) {\n // don't display any \"drop files to upload\" background text\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (dropArea && qq(dropArea).hasAttribute(HIDE_DROPZONE_ATTR)) {\n // If there is a drop area defined in the template, and the current UA doesn't support DnD,\n // and the drop area is marked as \"hide before enter\", ensure it is hidden as the DnD module\n // will not do this (since we will not be loading the DnD module)\n qq(dropArea).css({\n display: \"none\"\n });\n }\n }\n else if (qq(uploaderEl).hasAttribute(DROPZPONE_TEXT_ATTR) && dropArea) {\n dropTextEl = qq(dropArea).getFirstByClass(selectorClasses.dropText);\n dropTextEl && qq(dropTextEl).remove();\n }\n\n // Ensure the `showThumbnails` flag is only set if the thumbnail element\n // is present in the template AND the current UA is capable of generating client-side previews.\n thumbnail = qq(tempTemplateEl).getFirstByClass(selectorClasses.thumbnail);\n if (!showThumbnails) {\n thumbnail && qq(thumbnail).remove();\n }\n else if (thumbnail) {\n thumbnailMaxSize = parseInt(thumbnail.getAttribute(THUMBNAIL_MAX_SIZE_ATTR));\n // Only enforce max size if the attr value is non-zero\n thumbnailMaxSize = thumbnailMaxSize > 0 ? thumbnailMaxSize : null;\n\n serverScale = qq(thumbnail).hasAttribute(THUMBNAIL_SERVER_SCALE_ATTR);\n }\n showThumbnails = showThumbnails && thumbnail;\n\n isEditElementsExist = qq(tempTemplateEl).getByClass(selectorClasses.editFilenameInput).length > 0;\n isRetryElementExist = qq(tempTemplateEl).getByClass(selectorClasses.retry).length > 0;\n\n fileListNode = qq(tempTemplateEl).getFirstByClass(selectorClasses.list);\n /*jshint -W116*/\n if (fileListNode == null) {\n throw new Error(\"Could not find the file list container in the template!\");\n }\n\n fileListHtml = fileListNode.innerHTML;\n fileListNode.innerHTML = \"\";\n\n // We must call `createElement` in IE8 in order to target and hide any via CSS\n if (tempTemplateEl.getElementsByTagName(\"DIALOG\").length) {\n document.createElement(\"dialog\");\n }\n\n log(\"Template parsing complete\");\n\n return {\n template: qq.trimStr(tempTemplateEl.innerHTML),\n fileTemplate: qq.trimStr(fileListHtml)\n };\n },\n\n prependFile = function(el, index, fileList) {\n var parentEl = fileList,\n beforeEl = parentEl.firstChild;\n\n if (index > 0) {\n beforeEl = qq(parentEl).children()[index].nextSibling;\n\n }\n\n parentEl.insertBefore(el, beforeEl);\n },\n\n processNewQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n optFileOrBlob = queuedThumbRequest.optFileOrBlob,\n relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n maxSize: thumbnailMaxSize,\n orient: true,\n scale: true\n };\n\n if (qq.supportedFeatures.imagePreviews) {\n if (thumbnail) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n displayWaitingImg(thumbnail).done(function() {\n previewGeneration[id] = new qq.Promise();\n\n previewGeneration[id].done(function() {\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n });\n\n /* jshint eqnull: true */\n // If we've already generated an for this file, use the one that exists,\n // don't waste resources generating a new one.\n if (relatedThumbnailId != null) {\n useCachedPreview(id, relatedThumbnailId);\n }\n else {\n generateNewPreview(id, optFileOrBlob, spec);\n }\n });\n }\n }\n // File element in template may have been removed, so move on to next item in queue\n else {\n generateNextQueuedPreview();\n }\n }\n else if (thumbnail) {\n displayWaitingImg(thumbnail);\n generateNextQueuedPreview();\n }\n },\n\n processUpdateQueuedPreviewRequest = function(queuedThumbRequest) {\n var id = queuedThumbRequest.id,\n thumbnailUrl = queuedThumbRequest.thumbnailUrl,\n showWaitingImg = queuedThumbRequest.showWaitingImg,\n thumbnail = getThumbnail(id),\n spec = {\n customResizeFunction: queuedThumbRequest.customResizeFunction,\n scale: serverScale,\n maxSize: thumbnailMaxSize\n };\n\n if (thumbnail) {\n if (thumbnailUrl) {\n if (options.limits.maxThumbs && options.limits.maxThumbs <= generatedThumbnails) {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n else {\n if (showWaitingImg) {\n displayWaitingImg(thumbnail);\n }\n\n return options.imageGenerator.generate(thumbnailUrl, thumbnail, spec).then(\n function() {\n show(thumbnail);\n generatedThumbnails++;\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n },\n\n function() {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs);\n }\n );\n }\n }\n else {\n maybeSetDisplayNotAvailableImg(id, thumbnail);\n generateNextQueuedPreview();\n }\n }\n },\n\n setProgressBarWidth = function(id, percent) {\n var bar = getProgress(id),\n /* jshint eqnull:true */\n progressBarSelector = id == null ? selectorClasses.totalProgressBar : selectorClasses.progressBar;\n\n if (bar && !qq(bar).hasClass(progressBarSelector)) {\n bar = qq(bar).getFirstByClass(progressBarSelector);\n }\n\n if (bar) {\n qq(bar).css({width: percent + \"%\"});\n bar.setAttribute(\"aria-valuenow\", percent);\n }\n },\n\n show = function(el) {\n el && qq(el).removeClass(options.classes.hide);\n },\n\n useCachedPreview = function(targetThumbnailId, cachedThumbnailId) {\n var targetThumbnail = getThumbnail(targetThumbnailId),\n cachedThumbnail = getThumbnail(cachedThumbnailId);\n\n log(qq.format(\"ID {} is the same file as ID {}. Will use generated thumbnail from ID {} instead.\", targetThumbnailId, cachedThumbnailId, cachedThumbnailId));\n\n // Generation of the related thumbnail may still be in progress, so, wait until it is done.\n previewGeneration[cachedThumbnailId].then(function() {\n generatedThumbnails++;\n previewGeneration[targetThumbnailId].success();\n log(qq.format(\"Now using previously generated thumbnail created for ID {} on ID {}.\", cachedThumbnailId, targetThumbnailId));\n targetThumbnail.src = cachedThumbnail.src;\n show(targetThumbnail);\n },\n function() {\n previewGeneration[targetThumbnailId].failure();\n if (!options.placeholders.waitUntilUpdate) {\n maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail);\n }\n });\n };\n\n qq.extend(options, spec);\n log = options.log;\n\n // No need to worry about conserving CPU or memory on older browsers,\n // since there is no ability to preview, and thumbnail display is primitive and quick.\n if (!qq.supportedFeatures.imagePreviews) {\n options.limits.timeBetweenThumbs = 0;\n options.limits.maxThumbs = 0;\n }\n\n container = options.containerEl;\n showThumbnails = options.imageGenerator !== undefined;\n templateHtml = parseAndGetTemplate();\n\n cacheThumbnailPlaceholders();\n\n qq.extend(this, {\n render: function() {\n log(\"Rendering template in DOM.\");\n\n generatedThumbnails = 0;\n\n container.innerHTML = templateHtml.template;\n hide(getDropProcessing());\n this.hideTotalProgress();\n fileList = options.fileContainerEl || getTemplateEl(container, selectorClasses.list);\n\n log(\"Template rendering complete\");\n },\n\n renderFailure: function(message) {\n var cantRenderEl = qq.toElement(message);\n container.innerHTML = \"\";\n container.appendChild(cantRenderEl);\n },\n\n reset: function() {\n this.render();\n },\n\n clearFiles: function() {\n fileList.innerHTML = \"\";\n },\n\n disableCancel: function() {\n isCancelDisabled = true;\n },\n\n addFile: function(id, name, prependInfo, hideForever, batch) {\n var fileEl = qq.toElement(templateHtml.fileTemplate),\n fileNameEl = getTemplateEl(fileEl, selectorClasses.file),\n uploaderEl = getTemplateEl(container, selectorClasses.uploader),\n fileContainer = batch ? fileBatch.content : fileList,\n thumb;\n\n if (batch) {\n fileBatch.map[id] = fileEl;\n }\n\n qq(fileEl).addClass(FILE_CLASS_PREFIX + id);\n uploaderEl.removeAttribute(DROPZPONE_TEXT_ATTR);\n\n if (fileNameEl) {\n qq(fileNameEl).setText(name);\n fileNameEl.setAttribute(\"title\", name);\n }\n\n fileEl.setAttribute(FILE_ID_ATTR, id);\n\n if (prependInfo) {\n prependFile(fileEl, prependInfo.index, fileContainer);\n }\n else {\n fileContainer.appendChild(fileEl);\n }\n\n if (hideForever) {\n fileEl.style.display = \"none\";\n qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);\n }\n else {\n hide(getProgress(id));\n hide(getSize(id));\n hide(getDelete(id));\n hide(getRetry(id));\n hide(getPause(id));\n hide(getContinue(id));\n\n if (isCancelDisabled) {\n this.hideCancel(id);\n }\n\n thumb = getThumbnail(id);\n if (thumb && !thumb.src) {\n cachedWaitingForThumbnailImg.then(function(waitingImg) {\n thumb.src = waitingImg.src;\n if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {\n qq(thumb).css({\n maxHeight: waitingImg.style.maxHeight,\n maxWidth: waitingImg.style.maxWidth\n });\n }\n\n show(thumb);\n });\n }\n }\n },\n\n addFileToCache: function(id, name, prependInfo, hideForever) {\n this.addFile(id, name, prependInfo, hideForever, true);\n },\n\n addCacheToDom: function() {\n fileList.appendChild(fileBatch.content);\n fileBatch.content = document.createDocumentFragment();\n fileBatch.map = {};\n },\n\n removeFile: function(id) {\n qq(getFile(id)).remove();\n },\n\n getFileId: function(el) {\n var currentNode = el;\n\n if (currentNode) {\n /*jshint -W116*/\n while (currentNode.getAttribute(FILE_ID_ATTR) == null) {\n currentNode = currentNode.parentNode;\n }\n\n return parseInt(currentNode.getAttribute(FILE_ID_ATTR));\n }\n },\n\n getFileList: function() {\n return fileList;\n },\n\n markFilenameEditable: function(id) {\n var filename = getFilename(id);\n\n filename && qq(filename).addClass(options.classes.editable);\n },\n\n updateFilename: function(id, name) {\n var filenameEl = getFilename(id);\n\n if (filenameEl) {\n qq(filenameEl).setText(name);\n filenameEl.setAttribute(\"title\", name);\n }\n },\n\n hideFilename: function(id) {\n hide(getFilename(id));\n },\n\n showFilename: function(id) {\n show(getFilename(id));\n },\n\n isFileName: function(el) {\n return qq(el).hasClass(selectorClasses.file);\n },\n\n getButton: function() {\n return options.button || getTemplateEl(container, selectorClasses.button);\n },\n\n hideDropProcessing: function() {\n hide(getDropProcessing());\n },\n\n showDropProcessing: function() {\n show(getDropProcessing());\n },\n\n getDropZone: function() {\n return getTemplateEl(container, selectorClasses.drop);\n },\n\n isEditFilenamePossible: function() {\n return isEditElementsExist;\n },\n\n hideRetry: function(id) {\n hide(getRetry(id));\n },\n\n isRetryPossible: function() {\n return isRetryElementExist;\n },\n\n showRetry: function(id) {\n show(getRetry(id));\n },\n\n getFileContainer: function(id) {\n return getFile(id);\n },\n\n showEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).addClass(options.classes.editable);\n },\n\n isHiddenForever: function(id) {\n return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);\n },\n\n hideEditIcon: function(id) {\n var icon = getEditIcon(id);\n\n icon && qq(icon).removeClass(options.classes.editable);\n },\n\n isEditIcon: function(el) {\n return qq(el).hasClass(selectorClasses.editNameIcon, true);\n },\n\n getEditInput: function(id) {\n return getTemplateEl(getFile(id), selectorClasses.editFilenameInput);\n },\n\n isEditInput: function(el) {\n return qq(el).hasClass(selectorClasses.editFilenameInput, true);\n },\n\n updateProgress: function(id, loaded, total) {\n var bar = getProgress(id),\n percent;\n\n if (bar && total > 0) {\n percent = Math.round(loaded / total * 100);\n\n if (percent === 100) {\n hide(bar);\n }\n else {\n show(bar);\n }\n\n setProgressBarWidth(id, percent);\n }\n },\n\n updateTotalProgress: function(loaded, total) {\n this.updateProgress(null, loaded, total);\n },\n\n hideProgress: function(id) {\n var bar = getProgress(id);\n\n bar && hide(bar);\n },\n\n hideTotalProgress: function() {\n this.hideProgress();\n },\n\n resetProgress: function(id) {\n setProgressBarWidth(id, 0);\n this.hideTotalProgress(id);\n },\n\n resetTotalProgress: function() {\n this.resetProgress();\n },\n\n showCancel: function(id) {\n if (!isCancelDisabled) {\n var cancel = getCancel(id);\n\n cancel && qq(cancel).removeClass(options.classes.hide);\n }\n },\n\n hideCancel: function(id) {\n hide(getCancel(id));\n },\n\n isCancel: function(el) {\n return qq(el).hasClass(selectorClasses.cancel, true);\n },\n\n allowPause: function(id) {\n show(getPause(id));\n hide(getContinue(id));\n },\n\n uploadPaused: function(id) {\n this.setStatusText(id, options.text.paused);\n this.allowContinueButton(id);\n hide(getSpinner(id));\n },\n\n hidePause: function(id) {\n hide(getPause(id));\n },\n\n isPause: function(el) {\n return qq(el).hasClass(selectorClasses.pause, true);\n },\n\n isContinueButton: function(el) {\n return qq(el).hasClass(selectorClasses.continueButton, true);\n },\n\n allowContinueButton: function(id) {\n show(getContinue(id));\n hide(getPause(id));\n },\n\n uploadContinued: function(id) {\n this.setStatusText(id, \"\");\n this.allowPause(id);\n show(getSpinner(id));\n },\n\n showDeleteButton: function(id) {\n show(getDelete(id));\n },\n\n hideDeleteButton: function(id) {\n hide(getDelete(id));\n },\n\n isDeleteButton: function(el) {\n return qq(el).hasClass(selectorClasses.deleteButton, true);\n },\n\n isRetry: function(el) {\n return qq(el).hasClass(selectorClasses.retry, true);\n },\n\n updateSize: function(id, text) {\n var size = getSize(id);\n\n if (size) {\n show(size);\n qq(size).setText(text);\n }\n },\n\n setStatusText: function(id, text) {\n var textEl = getTemplateEl(getFile(id), selectorClasses.statusText);\n\n if (textEl) {\n /*jshint -W116*/\n if (text == null) {\n qq(textEl).clearText();\n }\n else {\n qq(textEl).setText(text);\n }\n }\n },\n\n hideSpinner: function(id) {\n qq(getFile(id)).removeClass(IN_PROGRESS_CLASS);\n hide(getSpinner(id));\n },\n\n showSpinner: function(id) {\n qq(getFile(id)).addClass(IN_PROGRESS_CLASS);\n show(getSpinner(id));\n },\n\n generatePreview: function(id, optFileOrBlob, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({id: id, customResizeFunction: customResizeFunction, optFileOrBlob: optFileOrBlob});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {\n if (!this.isHiddenForever(id)) {\n thumbGenerationQueue.push({customResizeFunction: customResizeFunction, update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});\n !thumbnailQueueMonitorRunning && generateNextQueuedPreview();\n }\n },\n\n hasDialog: function(type) {\n return qq.supportedFeatures.dialogElement && !!getDialog(type);\n },\n\n showDialog: function(type, message, defaultValue) {\n var dialog = getDialog(type),\n messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage),\n inputEl = dialog.getElementsByTagName(\"INPUT\")[0],\n cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton),\n okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton),\n promise = new qq.Promise(),\n\n closeHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.removeEventListener(\"click\", okClickHandler);\n promise.failure();\n },\n\n cancelClickHandler = function() {\n cancelBtn.removeEventListener(\"click\", cancelClickHandler);\n dialog.close();\n },\n\n okClickHandler = function() {\n dialog.removeEventListener(\"close\", closeHandler);\n okBtn.removeEventListener(\"click\", okClickHandler);\n dialog.close();\n\n promise.success(inputEl && inputEl.value);\n };\n\n dialog.addEventListener(\"close\", closeHandler);\n cancelBtn.addEventListener(\"click\", cancelClickHandler);\n okBtn && okBtn.addEventListener(\"click\", okClickHandler);\n\n if (inputEl) {\n inputEl.value = defaultValue;\n }\n messageEl.textContent = message;\n\n dialog.showModal();\n\n return promise;\n }\n });\n};\n","/*globals qq */\n// Base handler for UI (FineUploader mode) events.\n// Some more specific handlers inherit from this one.\nqq.UiEventHandler = function(s, protectedApi) {\n \"use strict\";\n\n var disposer = new qq.DisposeSupport(),\n spec = {\n eventType: \"click\",\n attachTo: null,\n onHandled: function(target, event) {}\n };\n\n // This makes up the \"public\" API methods that will be accessible\n // to instances constructing a base or child handler\n qq.extend(this, {\n addHandler: function(element) {\n addHandler(element);\n },\n\n dispose: function() {\n disposer.dispose();\n }\n });\n\n function addHandler(element) {\n disposer.attach(element, spec.eventType, function(event) {\n // Only in IE: the `event` is a property of the `window`.\n event = event || window.event;\n\n // On older browsers, we must check the `srcElement` instead of the `target`.\n var target = event.target || event.srcElement;\n\n spec.onHandled(target, event);\n });\n }\n\n // These make up the \"protected\" API methods that children of this base handler will utilize.\n qq.extend(protectedApi, {\n getFileIdFromItem: function(item) {\n return item.qqFileId;\n },\n\n getDisposeSupport: function() {\n return disposer;\n }\n });\n\n qq.extend(spec, s);\n\n if (spec.attachTo) {\n addHandler(spec.attachTo);\n }\n};\n","/* global qq */\nqq.FileButtonsClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n onDeleteFile: function(fileId) {},\n onCancel: function(fileId) {},\n onRetry: function(fileId) {},\n onPause: function(fileId) {},\n onContinue: function(fileId) {},\n onGetName: function(fileId) {}\n },\n buttonHandlers = {\n cancel: function(id) { spec.onCancel(id); },\n retry: function(id) { spec.onRetry(id); },\n deleteButton: function(id) { spec.onDeleteFile(id); },\n pause: function(id) { spec.onPause(id); },\n continueButton: function(id) { spec.onContinue(id); }\n };\n\n function examineEvent(target, event) {\n qq.each(buttonHandlers, function(buttonType, handler) {\n var firstLetterCapButtonType = buttonType.charAt(0).toUpperCase() + buttonType.slice(1),\n fileId;\n\n if (spec.templating[\"is\" + firstLetterCapButtonType](target)) {\n fileId = spec.templating.getFileId(target);\n qq.preventDefault(event);\n spec.log(qq.format(\"Detected valid file button click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n handler(fileId);\n return false;\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect click events on filename display elements.\nqq.FilenameClickHandler = function(s) {\n \"use strict\";\n\n var inheritedInternalApi = {},\n spec = {\n templating: null,\n log: function(message, lvl) {},\n classes: {\n file: \"qq-upload-file\",\n editNameIcon: \"qq-edit-filename-icon\"\n },\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {}\n };\n\n qq.extend(spec, s);\n\n // This will be called by the parent handler when a `click` event is received on the list element.\n function examineEvent(target, event) {\n if (spec.templating.isFileName(target) || spec.templating.isEditIcon(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n // We only allow users to change filenames of files that have been submitted but not yet uploaded.\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename click event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n qq.preventDefault(event);\n\n inheritedInternalApi.handleFilenameEdit(fileId, target, true);\n }\n }\n }\n\n spec.eventType = \"click\";\n spec.onHandled = examineEvent;\n\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n// Child of FilenameEditHandler. Used to detect focusin events on file edit input elements.\nqq.FilenameInputFocusInHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n onGetUploadStatus: function(fileId) {},\n log: function(message, lvl) {}\n };\n\n if (!inheritedInternalApi) {\n inheritedInternalApi = {};\n }\n\n // This will be called by the parent handler when a `focusin` event is received on the list element.\n function handleInputFocus(target, event) {\n if (spec.templating.isEditInput(target)) {\n var fileId = spec.templating.getFileId(target),\n status = spec.onGetUploadStatus(fileId);\n\n if (status === qq.status.SUBMITTED) {\n spec.log(qq.format(\"Detected valid filename input focus event on file '{}', ID: {}.\", spec.onGetName(fileId), fileId));\n inheritedInternalApi.handleFilenameEdit(fileId, target);\n }\n }\n }\n\n spec.eventType = \"focusin\";\n spec.onHandled = handleInputFocus;\n\n qq.extend(spec, s);\n qq.extend(this, new qq.FilenameEditHandler(spec, inheritedInternalApi));\n};\n","/*globals qq */\n/**\n * Child of FilenameInputFocusInHandler. Used to detect focus events on file edit input elements. This child module is only\n * needed for UAs that do not support the focusin event. Currently, only Firefox lacks this event.\n *\n * @param spec Overrides for default specifications\n */\nqq.FilenameInputFocusHandler = function(spec) {\n \"use strict\";\n\n spec.eventType = \"focus\";\n spec.attachTo = null;\n\n qq.extend(this, new qq.FilenameInputFocusInHandler(spec, {}));\n};\n","/*globals qq */\n// Handles edit-related events on a file item (FineUploader mode). This is meant to be a parent handler.\n// Children will delegate to this handler when specific edit-related actions are detected.\nqq.FilenameEditHandler = function(s, inheritedInternalApi) {\n \"use strict\";\n\n var spec = {\n templating: null,\n log: function(message, lvl) {},\n onGetUploadStatus: function(fileId) {},\n onGetName: function(fileId) {},\n onSetName: function(fileId, newName) {},\n onEditingStatusChange: function(fileId, isEditing) {}\n };\n\n function getFilenameSansExtension(fileId) {\n var filenameSansExt = spec.onGetName(fileId),\n extIdx = filenameSansExt.lastIndexOf(\".\");\n\n if (extIdx > 0) {\n filenameSansExt = filenameSansExt.substr(0, extIdx);\n }\n\n return filenameSansExt;\n }\n\n function getOriginalExtension(fileId) {\n var origName = spec.onGetName(fileId);\n return qq.getExtension(origName);\n }\n\n // Callback iff the name has been changed\n function handleNameUpdate(newFilenameInputEl, fileId) {\n var newName = newFilenameInputEl.value,\n origExtension;\n\n if (newName !== undefined && qq.trimStr(newName).length > 0) {\n origExtension = getOriginalExtension(fileId);\n\n if (origExtension !== undefined) {\n newName = newName + \".\" + origExtension;\n }\n\n spec.onSetName(fileId, newName);\n }\n\n spec.onEditingStatusChange(fileId, false);\n }\n\n // The name has been updated if the filename edit input loses focus.\n function registerInputBlurHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"blur\", function() {\n handleNameUpdate(inputEl, fileId);\n });\n }\n\n // The name has been updated if the user presses enter.\n function registerInputEnterKeyHandler(inputEl, fileId) {\n inheritedInternalApi.getDisposeSupport().attach(inputEl, \"keyup\", function(event) {\n\n var code = event.keyCode || event.which;\n\n if (code === 13) {\n handleNameUpdate(inputEl, fileId);\n }\n });\n }\n\n qq.extend(spec, s);\n\n spec.attachTo = spec.templating.getFileList();\n\n qq.extend(this, new qq.UiEventHandler(spec, inheritedInternalApi));\n\n qq.extend(inheritedInternalApi, {\n handleFilenameEdit: function(id, target, focusInput) {\n var newFilenameInputEl = spec.templating.getEditInput(id);\n\n spec.onEditingStatusChange(id, true);\n\n newFilenameInputEl.value = getFilenameSansExtension(id);\n\n if (focusInput) {\n newFilenameInputEl.focus();\n }\n\n registerInputBlurHandler(newFilenameInputEl, id);\n registerInputEnterKeyHandler(newFilenameInputEl, id);\n }\n });\n};\n"]}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader.min.css b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.min.css
new file mode 100644
index 000000000000..488d8eba2c1e
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.min.css
@@ -0,0 +1 @@
+.qq-uploader{position:relative;width:100%}.qq-upload-button{display:block;width:105px;padding:7px 0;text-align:center;background:#800;border-bottom:1px solid #DDD;color:#FFF}.qq-upload-button-hover{background:#C00}.qq-upload-button-focus{outline:#000 dotted 1px}.qq-upload-drop-area,.qq-upload-extra-drop-area{position:absolute;top:0;left:0;width:100%;height:100%;min-height:30px;z-index:2;background:#FF9797;text-align:center}.qq-upload-drop-area span{display:block;position:absolute;top:50%;width:100%;margin-top:-8px;font-size:16px}.qq-upload-extra-drop-area{position:relative;margin-top:50px;font-size:16px;padding-top:30px;height:20px;min-height:40px}.qq-upload-drop-area-active{background:#FF7171}.qq-upload-list{margin:0;padding:0;list-style:none}.qq-upload-list li{margin:0;padding:9px;line-height:15px;font-size:16px;background-color:#FFF0BD}.qq-upload-cancel,.qq-upload-continue,.qq-upload-delete,.qq-upload-failed-text,.qq-upload-file,.qq-upload-pause,.qq-upload-retry,.qq-upload-size,.qq-upload-spinner{margin-right:12px;display:inline}.qq-upload-spinner{display:inline-block;background:url(loading.gif);width:15px;height:15px;vertical-align:text-bottom}.qq-drop-processing{display:block}.qq-drop-processing-spinner{display:inline-block;background:url(processing.gif);width:24px;height:24px;vertical-align:text-bottom}.qq-upload-continue,.qq-upload-delete,.qq-upload-pause{display:inline}.qq-upload-cancel,.qq-upload-continue,.qq-upload-delete,.qq-upload-pause,.qq-upload-retry{color:#000}.qq-upload-cancel,.qq-upload-continue,.qq-upload-delete,.qq-upload-pause,.qq-upload-retry,.qq-upload-size{font-size:12px;font-weight:400}.qq-upload-failed-text{display:none;font-style:italic;font-weight:700}.qq-upload-failed-icon{display:none;width:15px;height:15px;vertical-align:text-bottom}.qq-upload-fail .qq-upload-failed-text{display:inline}.qq-upload-retrying .qq-upload-failed-text{display:inline;color:#D60000}.qq-upload-list li.qq-upload-success{background-color:#5DA30C;color:#FFF}.qq-upload-list li.qq-upload-fail{background-color:#D60000;color:#FFF}.qq-progress-bar{display:block;background:-moz-linear-gradient(top,rgba(30,87,153,1) 0,rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%,rgba(125,185,232,1) 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,rgba(30,87,153,1)),color-stop(50%,rgba(41,137,216,1)),color-stop(51%,rgba(32,124,202,1)),color-stop(100%,rgba(125,185,232,1)));background:-webkit-linear-gradient(top,rgba(30,87,153,1) 0,rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%,rgba(125,185,232,1) 100%);background:-o-linear-gradient(top,rgba(30,87,153,1) 0,rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%,rgba(125,185,232,1) 100%);background:-ms-linear-gradient(top,rgba(30,87,153,1) 0,rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%,rgba(125,185,232,1) 100%);background:linear-gradient(to bottom,rgba(30,87,153,1) 0,rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%,rgba(125,185,232,1) 100%);width:0;height:15px;border-radius:6px;margin-bottom:3px}.qq-total-progress-bar{height:25px;border-radius:9px}.qq-total-progress-bar-container{margin:9px}INPUT.qq-edit-filename{position:absolute;opacity:0;filter:alpha(opacity=0);z-index:-1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"}.qq-upload-file.qq-editable{cursor:pointer}.qq-edit-filename-icon.qq-editable{display:inline-block;cursor:pointer}.qq-hide,.qq-uploader DIALOG{display:none}INPUT.qq-edit-filename.qq-editing{position:static;margin-top:-5px;margin-right:10px;margin-bottom:-5px;opacity:1;filter:alpha(opacity=100);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}.qq-edit-filename-icon{display:none;background:url(edit.gif);width:15px;height:15px;vertical-align:text-bottom;margin-right:5px}.qq-uploader DIALOG[open]{display:block}.qq-uploader DIALOG .qq-dialog-buttons{text-align:center;padding-top:10px}.qq-uploader DIALOG .qq-dialog-buttons BUTTON{margin-left:5px;margin-right:5px}.qq-uploader DIALOG .qq-dialog-message-selector{padding-bottom:10px}.qq-uploader DIALOG::backdrop{background-color:rgba(0,0,0,.7)}/*# sourceMappingURL=fine-uploader.min.css.map */
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader.min.css.map b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.min.css.map
new file mode 100644
index 000000000000..3ee17ba9be54
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.min.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["_build/fine-uploader.css"],"names":[],"mappings":"AAAA,aACI,SAAU,SACV,MAAO,KAEX,kBACI,QAAS,MACT,MAAO,MACP,QAAS,IAAI,EACb,WAAY,OACZ,WAAY,KACZ,cAAe,IAAI,MAAM,KACzB,MAAO,KAEX,wBACI,WAAY,KAEhB,wBACI,QAAoB,KAAP,OAAJ,IAEb,qBAAsB,2BAClB,SAAU,SACV,IAAK,EACL,KAAM,EACN,MAAO,KACP,OAAQ,KACR,WAAY,KACZ,QAAS,EACT,WAAY,QACZ,WAAY,OAEhB,0BACI,QAAS,MACT,SAAU,SACV,IAAK,IACL,MAAO,KACP,WAAY,KACZ,UAAW,KAEf,2BACI,SAAU,SACV,WAAY,KACZ,UAAW,KACX,YAAa,KACb,OAAQ,KACR,WAAY,KAEhB,4BACI,WAAY,QAEhB,gBACI,OAAQ,EACR,QAAS,EACT,WAAY,KAEhB,mBACI,OAAQ,EACR,QAAS,IACT,YAAa,KACb,UAAW,KACX,iBAAkB,QAGtB,kBACqC,oBAArC,kBADqC,uBADrC,gBAEmB,iBADA,iBADkB,gBAApB,mBAGb,aAAc,KACd,QAAS,OAIb,mBACI,QAAS,aACT,WAAY,iBACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAEpB,oBACI,QAAS,MAEb,4BACI,QAAS,aACT,WAAY,oBACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAGiB,oBAArC,kBAAmB,iBACf,QAAS,OAGwB,kBACnB,oBADA,kBAClB,iBADA,iBAEI,MAAO,KAGM,kBACoB,oBAArC,kBAAmB,iBADiB,iBAApC,gBAEI,UAAW,KACX,YAAa,IAEjB,uBACI,QAAS,KACT,WAAY,OACZ,YAAa,IAEjB,uBACI,QAAQ,KACR,MAAM,KACN,OAAO,KACP,eAAe,YAEnB,uCACI,QAAS,OAEb,2CACI,QAAS,OACT,MAAO,QAEX,qCACI,iBAAkB,QAClB,MAAO,KAEX,kCACI,iBAAkB,QAClB,MAAO,KAEX,iBACI,QAAS,MACT,WAAY,qHACZ,WAAwB,yLACxB,WAA8C,wHAC9C,WAAyE,mHACzE,WAA4F,oHAC5F,WAAwG,sHACxG,MAA6G,EAC7G,OAAQ,KACR,cAAe,IACf,cAAe,IAGnB,uBACI,OAAQ,KACR,cAAe,IAGnB,iCACI,OAAQ,IAGZ,uBACI,SAAU,SACV,QAAS,EACT,OAAQ,iBACR,QAAS,GACT,WAAY,qDAGhB,4BACI,OAAQ,QAGZ,mCACI,QAAS,aACT,OAAQ,QAuBZ,SAaA,oBACI,QAAS,KAlCb,kCACI,SAAU,OACV,WAAY,KACZ,aAAc,KACd,cAAe,KAEf,QAAS,EACT,OAAQ,mBACR,WAAY,uDAGhB,uBACI,QAAS,KACT,WAAY,cACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAChB,aAAc,IAoBlB,0BACI,QAAS,MAGb,uCACI,WAAY,OACZ,YAAa,KAGjB,8CACI,YAAa,IACb,aAAc,IAGlB,gDACI,eAAgB,KAGpB,8BACI,iBAAkB"}
\ No newline at end of file
diff --git a/libs/bower/bower_components/fine-uploader/dist/fine-uploader.min.js b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.min.js
new file mode 100644
index 000000000000..0f7f7255db87
--- /dev/null
+++ b/libs/bower/bower_components/fine-uploader/dist/fine-uploader.min.js
@@ -0,0 +1,7 @@
+// Fine Uploader 5.13.0 - (c) 2013-present Widen Enterprises, Inc. MIT licensed. http://fineuploader.com
+!function(global){var qq=function(e){"use strict";return{hide:function(){return e.style.display="none",this},attach:function(t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n),function(){qq(e).detach(t,n)}},detach:function(t,n){return e.removeEventListener?e.removeEventListener(t,n,!1):e.attachEvent&&e.detachEvent("on"+t,n),this},contains:function(t){return!!t&&(e===t||(e.contains?e.contains(t):!!(8&t.compareDocumentPosition(e))))},insertBefore:function(t){return t.parentNode.insertBefore(e,t),this},remove:function(){return e.parentNode.removeChild(e),this},css:function(t){if(null==e.style)throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");return null!=t.opacity&&"string"!=typeof e.style.opacity&&"undefined"!=typeof e.filters&&(t.filter="alpha(opacity="+Math.round(100*t.opacity)+")"),qq.extend(e.style,t),this},hasClass:function(t,n){var i=new RegExp("(^| )"+t+"( |$)");return i.test(e.className)||!(!n||!i.test(e.parentNode.className))},addClass:function(t){return qq(e).hasClass(t)||(e.className+=" "+t),this},removeClass:function(t){var n=new RegExp("(^| )"+t+"( |$)");return e.className=e.className.replace(n," ").replace(/^\s+|\s+$/g,""),this},getByClass:function(t,n){var i,o=[];return n&&e.querySelector?e.querySelector("."+t):e.querySelectorAll?e.querySelectorAll("."+t):(i=e.getElementsByTagName("*"),qq.each(i,function(e,n){qq(n).hasClass(t)&&o.push(n)}),n?o[0]:o)},getFirstByClass:function(t){return qq(e).getByClass(t,!0)},children:function(){for(var t=[],n=e.firstChild;n;)1===n.nodeType&&t.push(n),n=n.nextSibling;return t},setText:function(t){return e.innerText=t,e.textContent=t,this},clearText:function(){return qq(e).setText("")},hasAttribute:function(t){var n;return e.hasAttribute?!!e.hasAttribute(t)&&null==/^false$/i.exec(e.getAttribute(t)):(n=e[t],void 0!==n&&null==/^false$/i.exec(n))}}};!function(){"use strict";qq.canvasToBlob=function(e,t,n){return qq.dataUriToBlob(e.toDataURL(t,n))},qq.dataUriToBlob=function(e){var t,n,i,o,r=function(e,t){var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,i=n&&new n;return i?(i.append(e),i.getBlob(t)):new Blob([e],{type:t})};return n=e.split(",")[0].indexOf("base64")>=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),o=e.split(",")[0].split(":")[1].split(";")[0],t=new ArrayBuffer(n.length),i=new Uint8Array(t),qq.each(n,function(e,t){i[e]=t.charCodeAt(0)}),r(t,o)},qq.log=function(e,t){window.console&&(t&&"info"!==t?window.console[t]?window.console[t](e):window.console.log("<"+t+"> "+e):window.console.log(e))},qq.isObject=function(e){return e&&!e.nodeType&&"[object Object]"===Object.prototype.toString.call(e)},qq.isFunction=function(e){return"function"==typeof e},qq.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)||e&&window.ArrayBuffer&&e.buffer&&e.buffer.constructor===ArrayBuffer},qq.isItemList=function(e){return"[object DataTransferItemList]"===Object.prototype.toString.call(e)},qq.isNodeList=function(e){return"[object NodeList]"===Object.prototype.toString.call(e)||e.item&&e.namedItem},qq.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},qq.trimStr=function(e){return String.prototype.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},qq.format=function(e){var t=Array.prototype.slice.call(arguments,1),n=e,i=n.indexOf("{}");return qq.each(t,function(e,t){var o=n.substring(0,i),r=n.substring(i+2);if(n=o+t+r,i=n.indexOf("{}",i+t.length),i<0)return!1}),n},qq.isFile=function(e){return window.File&&"[object File]"===Object.prototype.toString.call(e)},qq.isFileList=function(e){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(e)},qq.isFileOrInput=function(e){return qq.isFile(e)||qq.isInput(e)},qq.isInput=function(e,t){var n=function(e){var n=e.toLowerCase();return t?"file"!==n:"file"===n};return!!(window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(e)&&e.type&&n(e.type))||!!(e.tagName&&"input"===e.tagName.toLowerCase()&&e.type&&n(e.type))},qq.isBlob=function(e){if(window.Blob&&"[object Blob]"===Object.prototype.toString.call(e))return!0},qq.isXhrUploadSupported=function(){var e=document.createElement("input");return e.type="file",void 0!==e.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&"undefined"!=typeof qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(e){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(e){return e.items&&e.items.length>0&&e.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(e,t,n){var i=e.slice||e.mozSlice||e.webkitSlice;return i.call(e,t,n)},qq.arrayBufferToHex=function(e){var t="",n=new Uint8Array(e);return qq.each(n,function(e,n){var i=n.toString(16);i.length<2&&(i="0"+i),t+=i}),t},qq.readBlobToHex=function(e,t,n){var i=qq.sliceBlob(e,t,t+n),o=new FileReader,r=new qq.Promise;return o.onload=function(){r.success(qq.arrayBufferToHex(o.result))},o.onerror=r.failure,o.readAsArrayBuffer(i),r},qq.extend=function(e,t,n){return qq.each(t,function(t,i){n&&qq.isObject(i)?(void 0===e[t]&&(e[t]={}),qq.extend(e[t],i,!0)):e[t]=i}),e},qq.override=function(e,t){var n={},i=t(n);return qq.each(i,function(t,i){void 0!==e[t]&&(n[t]=e[t]),e[t]=i}),e},qq.indexOf=function(e,t,n){if(e.indexOf)return e.indexOf(t,n);n=n||0;var i=e.length;for(n<0&&(n+=i);n=0},qq.safari=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Apple")!==-1},qq.chrome=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Google")!==-1},qq.opera=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Opera")!==-1},qq.firefox=function(){return!qq.edge()&&!qq.ie11()&&navigator.userAgent.indexOf("Mozilla")!==-1&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return navigator.userAgent.toLowerCase().indexOf("android")!==-1},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 6_")!==-1},qq.ios7=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 7_")!==-1},qq.ios8=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_")!==-1},qq.ios800=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_0 ")!==-1},qq.ios=function(){return navigator.userAgent.indexOf("iPad")!==-1||navigator.userAgent.indexOf("iPod")!==-1||navigator.userAgent.indexOf("iPhone")!==-1},qq.iosChrome=function(){return qq.ios()&&navigator.userAgent.indexOf("CriOS")!==-1},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&navigator.userAgent.indexOf("Safari")!==-1},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},qq.toElement=function(){var e=document.createElement("div");return function(t){e.innerHTML=t;var n=e.firstChild;return e.removeChild(n),n}}(),qq.each=function(e,t){var n,i;if(e)if(window.Storage&&e.constructor===window.Storage)for(n=0;n